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 2012/11/14 22:23:35 UTC

svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Author: lu4242
Date: Wed Nov 14 21:23:35 2012
New Revision: 1409414

URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
Log:
MYFACES-3638 revert commit 1408993 to include later solution without refactoring.

Added:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
      - copied unchanged from r1408992, myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
Removed:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
Modified:
    myfaces/core/trunk/impl/   (props changed)
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java

Propchange: myfaces/core/trunk/impl/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed Nov 14 21:23:35 2012
@@ -7,7 +7,8 @@ target
 *.iml
 *.ipr
 *.iws
-.idea
 .settings
+
 cobertura.ser
+
 test-output

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java Wed Nov 14 21:23:35 2012
@@ -30,16 +30,21 @@ import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Random;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.GZIPOutputStream;
+import javax.faces.application.ProjectStage;
 
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
 
 import org.apache.commons.collections.map.AbstractReferenceMap;
 import org.apache.commons.collections.map.ReferenceMap;
@@ -52,22 +57,22 @@ import org.apache.myfaces.shared.util.We
 class ServerSideStateCacheImpl extends StateCache<Object, Object>
 {
     private static final Logger log = Logger.getLogger(ServerSideStateCacheImpl.class.getName());
-
-    private static final String SERIALIZED_VIEW_SESSION_ATTR=
+    
+    private static final String SERIALIZED_VIEW_SESSION_ATTR= 
         ServerSideStateCacheImpl.class.getName() + ".SERIALIZED_VIEW";
-
-    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
+    
+    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR = 
         ServerSideStateCacheImpl.class.getName() + ".RESTORED_SERIALIZED_VIEW";
 
-    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
+    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR = 
         ServerSideStateCacheImpl.class.getName() + ".RESTORED_VIEW_KEY";
-
+    
     /**
      * Defines the amount (default = 20) of the latest views are stored in session.
-     *
+     * 
      * <p>Only applicable if state saving method is "server" (= default).
      * </p>
-     *
+     * 
      */
     @JSFWebConfigParam(defaultValue="20",since="1.1", classType="java.lang.Integer", group="state", tags="performance")
     private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM = "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
@@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
     /**
      * 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>Only applicable if state saving method is "server" (= default). For example, if this param has value = 2 and
+     * 
+     * <p>Only applicable if state saving method is "server" (= default). 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
@@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends S
     @JSFWebConfigParam(since="2.0.6", classType="java.lang.Integer", group="state", tags="performance")
     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;
 
     /**
-     * Indicate if the state should be serialized before save it on the session.
+     * Indicate if the state should be serialized before save it on the session. 
      * <p>
      * 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.
@@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends S
 
     /**
      * Indicates that the serialized state will be compressed before it is written to the session. By default true.
-     *
+     * 
      * 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.
@@ -140,38 +145,38 @@ class ServerSideStateCacheImpl extends S
      * <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>
+     * <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", group="state", tags="performance")
     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
+     * 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";
 
     /**
      * 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.
-     *
+     * 
      * <p>
      * Only applicable if state saving method is "server" (= default).
      * The default value is false.</p>
@@ -183,84 +188,90 @@ class ServerSideStateCacheImpl extends S
     private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE = "none";
     private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM = "secureRandom";
     private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM = "random";
-
+    
     /**
      * Adds a random key to the generated view state session token.
      */
-    @JSFWebConfigParam(since="2.1.9, 2.0.15", expectedValues="secureRandom, random, none",
+    @JSFWebConfigParam(since="2.1.9, 2.0.15", expectedValues="secureRandom, random, none", 
             defaultValue="none", group="state")
     private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
             = "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
-    private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
+    private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT = 
             RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
 
     /**
      * Set the default length of the random key added to the view state session token.
-     * By default is 8.
+     * By default is 8. 
      */
     @JSFWebConfigParam(since="2.1.9, 2.0.15", defaultValue="8", group="state")
-    static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
+    private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM 
             = "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
-    static final int RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
+    private static final int RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
 
     /**
-     * Sets the random class to initialize the secure random id generator.
+     * Sets the random class to initialize the secure random id generator. 
      * By default it uses java.security.SecureRandom
      */
     @JSFWebConfigParam(since="2.1.9, 2.0.15", group="state")
-    static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
+    private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
             = "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
-
+    
     /**
      * Sets the random provider to initialize the secure random id generator.
      */
     @JSFWebConfigParam(since="2.1.9, 2.0.15", group="state")
-    static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
+    private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
             = "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
-
+    
     /**
-     * Sets the random algorithm to initialize the secure random id generator.
+     * Sets the random algorithm to initialize the secure random id generator. 
      * By default is SHA1PRNG
      */
     @JSFWebConfigParam(since="2.1.9, 2.0.15", defaultValue="SHA1PRNG", group="state")
-    static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
+    private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM 
             = "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
-
-
+    
+    
     private static final int UNCOMPRESSED_FLAG = 0;
     private static final int COMPRESSED_FLAG = 1;
-
+    
     private static final Object[] EMPTY_STATES = new Object[]{null, null};
 
+    //private static final int JSF_SEQUENCE_INDEX = 0;
+    
     private Boolean _useFlashScopePurgeViewsInSession = null;
-
+    
     private Integer _numberOfSequentialViewsInSession = null;
     private boolean _numberOfSequentialViewsInSessionSet = false;
 
+    //private final KeyFactory keyFactory;
     private SessionViewStorageFactory sessionViewStorageFactory;
 
     public ServerSideStateCacheImpl()
     {
         FacesContext facesContext = FacesContext.getCurrentInstance();
         String randomMode = WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
-                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
+                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM, 
                 RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
         if (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
         {
-            sessionViewStorageFactory = new SessionViewStorageFactory(
+            //keyFactory = new SecureRandomKeyFactory(facesContext);
+            sessionViewStorageFactory = new RandomSessionViewStorageFactory(
                     new SecureRandomKeyFactory(facesContext));
         }
         else if (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
         {
-            sessionViewStorageFactory = new SessionViewStorageFactory(
+            //keyFactory = new RandomKeyFactory(facesContext);
+            sessionViewStorageFactory = new RandomSessionViewStorageFactory(
                     new RandomKeyFactory(facesContext));
         }
         else
         {
-            sessionViewStorageFactory = new SessionViewStorageFactory(new CounterKeyFactory());
+            //keyFactory = new CounterKeyFactory();
+            sessionViewStorageFactory = new CounterSessionViewStorageFactory(new CounterKeyFactory());
         }
     }
-
+    
     //------------------------------------- METHODS COPIED FROM JspStateManagerImpl--------------------------------
 
     protected Object getServerStateId(FacesContext facesContext, Object state)
@@ -285,16 +296,16 @@ class ServerSideStateCacheImpl extends S
         }
 
         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()) &&
+                if (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) && 
                     Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
                             .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
                 {
@@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends S
                 }
             }
         }
-
+        
         SerializedViewKey nextKey = getSessionViewStorageFactory().createSerializedViewKey(
                 context, context.getViewRoot().getViewId(), getNextViewSequence(context));
         viewCollection.add(context, serializeView(context, serializedView), nextKey, key);
@@ -339,14 +350,14 @@ class ServerSideStateCacheImpl extends S
                 }
             }
             attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
-
+            
             if (getNumberOfSequentialViewsInSession(externalContext) != null &&
                 getNumberOfSequentialViewsInSession(externalContext) > 0)
             {
                 SerializedViewKey key = getSessionViewStorageFactory().
                         createSerializedViewKey(context, viewId, sequence);
                 attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
-
+                
                 if (isUseFlashScopePurgeViewsInSession(externalContext))
                 {
                     externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
@@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends S
                 //Object[] stateArray = (Object[]) serializedView;
 
                 ObjectOutputStream out = new ObjectOutputStream(os);
-
+                
                 out.writeObject(serializedView);
                 //out.writeObject(stateArray[0]);
                 //out.writeObject(stateArray[1]);
@@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends S
                     final ObjectInputStream in = new MyFacesObjectInputStream(is);
                     ois = in;
                     Object object = null;
-                    if (System.getSecurityManager() != null)
+                    if (System.getSecurityManager() != null) 
                     {
-                        object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
+                        object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() 
                         {
                             public Object run() throws PrivilegedActionException, IOException, ClassNotFoundException
                             {
@@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends S
                     }
                 }
             }
-            catch (PrivilegedActionException e)
+            catch (PrivilegedActionException e) 
             {
                 log.log(Level.SEVERE, "Exiting deserializeView - Could not deserialize state: " + e.getMessage(), e);
                 return null;
@@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends S
             return null;
         }
     }
-
+    
     protected static class SerializedViewCollection implements Serializable
     {
         private static final long serialVersionUID = -3734849062185115847L;
@@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends S
         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 =
+        
+        private final Map<SerializedViewKey, SerializedViewKey> _precedence = 
             new HashMap<SerializedViewKey, SerializedViewKey>();
 
         // old views will be hold as soft references which will be removed by
@@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends S
                 // into the map.
                 state = null;
             }
-
+            
             Integer maxCount = getNumberOfSequentialViewsInSession(context);
             if (maxCount != null)
             {
@@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends S
                   previousKey = _precedence.get(previousKey);
                   count++;
                 } while (previousKey != null && count < maxCount);
-
+                
                 if (previousKey != null)
                 {
                     SerializedViewKey keyToRemove = (SerializedViewKey) previousKey;
@@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends S
                         {
                             _serializedViews.remove(keyToRemove);
                         }
-
+                    
                         keyToRemove = _precedence.remove(keyToRemove);
                     }  while(keyToRemove != null);
                 }
@@ -680,11 +691,11 @@ class ServerSideStateCacheImpl extends S
             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,
+                    // 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
@@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends S
                 if (_serializedViews.containsKey(key) &&
                     !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
                 {
-
+                    
                     getOldSerializedViewsMap().put(key, _serializedViews.remove(key));
                 }
                 else
@@ -708,10 +719,10 @@ class ServerSideStateCacheImpl extends S
 
         protected Integer getNumberOfSequentialViewsInSession(FacesContext context)
         {
-            return WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
+            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
@@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends S
             FacesContext context = FacesContext.getCurrentInstance();
             if (_oldSerializedViews == null && context != null)
             {
-                String cacheMode = getCacheOldViewsInSessionMode(context);
+                String cacheMode = getCacheOldViewsInSessionMode(context); 
                 if (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
                 {
                     _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true);
@@ -773,13 +784,13 @@ class ServerSideStateCacheImpl extends S
                     _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
@@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends S
             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;
@@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends S
                 return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
             }
         }
-
+        
         public Object get(SerializedViewKey key)
         {
             Object value = _serializedViews.get(key);
@@ -846,7 +857,172 @@ class ServerSideStateCacheImpl extends S
         }
     }
 
+    /**
+     * Base implementation where all keys used to identify the state of a view should
+     * extend.
+     */
+    protected abstract static class SerializedViewKey implements Serializable
+    {
+    }
+
+    /**
+     * Implementation of SerializedViewKey, where the hashCode of the viewId is used
+     * and the sequenceId is a numeric value.
+     */
+    private static class IntIntSerializedViewKey extends SerializedViewKey 
+        implements Serializable
+    {
+        private static final long serialVersionUID = -1170697124386063642L;
+        
+        private final int _viewId;
+        private final int _sequenceId;
+        
+        public IntIntSerializedViewKey(int viewId, int sequence)
+        {
+            _sequenceId = sequence;
+            _viewId = viewId;
+        }
+
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (obj == null)
+            {
+                return false;
+            }
+            if (getClass() != obj.getClass())
+            {
+                return false;
+            }
+            final IntIntSerializedViewKey other = (IntIntSerializedViewKey) obj;
+            if (this._viewId != other._viewId)
+            {
+                return false;
+            }
+            if (this._sequenceId != other._sequenceId)
+            {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode()
+        {
+            int hash = 7;
+            hash = 83 * hash + this._viewId;
+            hash = 83 * hash + this._sequenceId;
+            return hash;
+        }
+    }
+
+    /**
+     * Implementation of SerializedViewKey, where the hashCode of the viewId is used
+     * and the sequenceId is a string value.
+     */
+    private static class IntByteArraySerializedViewKey extends SerializedViewKey
+        implements Serializable
+    {
+        private final int _viewId;
+        private final byte[] _sequenceId;
+        
+        public IntByteArraySerializedViewKey(int viewId, byte[] sequence)
+        {
+            _sequenceId = sequence;
+            _viewId = viewId;
+        }
+
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (obj == null)
+            {
+                return false;
+            }
+            if (getClass() != obj.getClass())
+            {
+                return false;
+            }
+            final IntByteArraySerializedViewKey other = (IntByteArraySerializedViewKey) obj;
+            if (this._viewId != other._viewId)
+            {
+                return false;
+            }
+            if (!Arrays.equals(this._sequenceId, other._sequenceId))
+            {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode()
+        {
+            int hash = 5;
+            hash = 37 * hash + this._viewId;
+            hash = 37 * hash + Arrays.hashCode(this._sequenceId);
+            return hash;
+        }
+    }
+    
+    
+    /**
+     * Implementation of SerializedViewKey, where the viewId and the sequenceId can be
+     * anything.
+     */
+    private static class ReferenceSerializedViewKey<I,K> extends SerializedViewKey
+        implements Serializable
+    {
+        private static final long serialVersionUID = -1170697124386063642L;
+
+        private final I _viewId;
+        private final K _sequenceId;
 
+        public ReferenceSerializedViewKey()
+        {
+            _sequenceId = null;
+            _viewId = null;
+        }
+        public ReferenceSerializedViewKey(I viewId, K sequence)
+        {
+            _sequenceId = sequence;
+            _viewId = viewId;
+        }
+
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (obj == null)
+            {
+                return false;
+            }
+            if (getClass() != obj.getClass())
+            {
+                return false;
+            }
+            final ReferenceSerializedViewKey<I, K> other = (ReferenceSerializedViewKey<I, K>) obj;
+            if (this._viewId != other._viewId && (this._viewId == null || !this._viewId.equals(other._viewId)))
+            {
+                return false;
+            }
+            if (this._sequenceId != other._sequenceId && 
+                (this._sequenceId == null || !this._sequenceId.equals(other._sequenceId)))
+            {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode()
+        {
+            int hash = 7;
+            hash = 83 * hash + (this._viewId != null ? this._viewId.hashCode() : 0);
+            hash = 83 * hash + (this._sequenceId != null ? this._sequenceId.hashCode() : 0);
+            return hash;
+        }
+    }
+    
     //------------------------------------- METHOD FROM StateCache ------------------------------------------------
 
     @Override
@@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl extends S
         }
         //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);
     }
 
@@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl extends S
     {
         return getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
     }
-
+    
     @Override
     public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
     {
@@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl extends S
     }
 
     //------------------------------------- Custom methods -----------------------------------------------------
-
+    
     private boolean isUseFlashScopePurgeViewsInSession(ExternalContext externalContext)
     {
         if (_useFlashScopePurgeViewsInSession == null)
@@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl extends S
         }
         return _useFlashScopePurgeViewsInSession;
     }
-
+    
     private Integer getNumberOfSequentialViewsInSession(ExternalContext externalContext)
     {
         if (!_numberOfSequentialViewsInSessionSet)
         {
             _numberOfSequentialViewsInSession = WebConfigParamUtils.getIntegerInitParameter(
-                    externalContext,
+                    externalContext, 
                     NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
             _numberOfSequentialViewsInSessionSet = true;
         }
         return _numberOfSequentialViewsInSession;
     }
-
+    
     protected KeyFactory getKeyFactory(FacesContext facesContext)
     {
         //return keyFactory;
         return sessionViewStorageFactory.getKeyFactory();
     }
-
+    
     protected SessionViewStorageFactory getSessionViewStorageFactory()
     {
         return sessionViewStorageFactory;
     }
+            
 
+    protected abstract static class KeyFactory<K, V>
+    {
+        
+        /**
+         * Generates a unique key per session 
+         * 
+         * @param facesContext
+         * @return 
+         */
+        public abstract K generateKey(FacesContext facesContext);
+        
+        /**
+         * Encode a Key into a value that will be used as view state session token
+         * 
+         * @param key
+         * @return 
+         */
+        public abstract V encode(K key);
 
+        /**
+         * Decode a view state session token into a key
+         * 
+         * @param value
+         * @return 
+         */
+        public abstract K decode(V value);
+
+    }
+
+    private static class CounterKeyFactory extends KeyFactory<Integer, String>
+    {
+        /**
+         * Take the counter from session scope and increment
+         * 
+         * @param facesContext
+         * @return 
+         */
+        @Override
+        public Integer generateKey(FacesContext facesContext)
+        {
+            ExternalContext externalContext = facesContext.getExternalContext();
+            Object sessionObj = externalContext.getSession(true);
+            Integer sequence = null;
+            synchronized(sessionObj) // synchronized to increase sequence if multiple requests
+                                    // are handled at the same time for the session
+            {
+                Map<String, Object> map = externalContext.getSessionMap();
+                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);
+            }
+            return sequence;
+        }
+        
+        public String encode(Integer sequence)
+        {
+            return Integer.toString(sequence, Character.MAX_RADIX);
+        }
+                
+        public Integer decode(String serverStateId)
+        {
+             return Integer.valueOf((String) serverStateId, Character.MAX_RADIX);
+        }
+    }
+    
+    /**
+     * This factory generate a key composed by a counter and a random number. The
+     * counter ensures uniqueness, and the random number prevents guess the next
+     * session token.
+     */
+    private static class SecureRandomKeyFactory extends KeyFactory<byte[], String>
+    {
+        private final SessionIdGenerator sessionIdGenerator;
+        private final int length;
+
+        public SecureRandomKeyFactory(FacesContext facesContext)
+        {
+            length = WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
+                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM, 
+                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
+            sessionIdGenerator = new SessionIdGenerator();
+            sessionIdGenerator.setSessionIdLength(length);
+            String secureRandomClass = WebConfigParamUtils.getStringInitParameter(
+                    facesContext.getExternalContext(),
+                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
+            if (secureRandomClass != null)
+            {
+                sessionIdGenerator.setSecureRandomClass(secureRandomClass);
+            }
+            String secureRandomProvider = WebConfigParamUtils.getStringInitParameter(
+                    facesContext.getExternalContext(),
+                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
+            if (secureRandomProvider != null)
+            {
+                sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
+            }
+            String secureRandomAlgorithm = WebConfigParamUtils.getStringInitParameter(
+                    facesContext.getExternalContext(), 
+                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
+            if (secureRandomAlgorithm != null)
+            {
+                sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
+            }
+        }
+        
+        public Integer generateCounterKey(FacesContext facesContext)
+        {
+            ExternalContext externalContext = facesContext.getExternalContext();
+            Object sessionObj = externalContext.getSession(true);
+            Integer sequence = null;
+            synchronized(sessionObj) // synchronized to increase sequence if multiple requests
+                                    // are handled at the same time for the session
+            {
+                Map<String, Object> map = externalContext.getSessionMap();
+                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);
+            }
+            return sequence;
+        }
+
+        @Override
+        public byte[] generateKey(FacesContext facesContext)
+        {
+            byte[] array = new byte[length];
+            byte[] key = new byte[length+4];
+            
+            sessionIdGenerator.getRandomBytes(array);
+            for (int i = 0; i < array.length; i++)
+            {
+                key[i] = array[i];
+            }
+            int value = generateCounterKey(facesContext);
+            key[array.length] =  (byte) (value >>> 24);
+            key[array.length+1] =  (byte) (value >>> 16);
+            key[array.length+2] =  (byte) (value >>> 8);
+            key[array.length+3] =  (byte) (value);
+            
+            return key;
+        }
+
+        @Override
+        public String encode(byte[] key)
+        {
+            return new String(Hex.encodeHex(key));
+        }
+        
+        @Override
+        public byte[] decode(String value)
+        {
+            try
+            {
+                return Hex.decodeHex(value.toCharArray());
+            }
+            catch (DecoderException ex)
+            {
+                // Cannot decode, ignore silently, later it will be handled as
+                // ViewExpiredException
+            }
+            return null;
+        }
+    }
+    
+    private static class RandomKeyFactory extends KeyFactory<byte[], String>
+    {
+        private final Random random;
+        private final int length;
+        
+        public RandomKeyFactory(FacesContext facesContext)
+        {
+            length = WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
+                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM, 
+                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
+            random = new Random(((int)System.nanoTime())+this.hashCode());
+        }
+        
+        public Integer generateCounterKey(FacesContext facesContext)
+        {
+            ExternalContext externalContext = facesContext.getExternalContext();
+            Object sessionObj = externalContext.getSession(true);
+            Integer sequence = null;
+            synchronized(sessionObj) // synchronized to increase sequence if multiple requests
+                                    // are handled at the same time for the session
+            {
+                Map<String, Object> map = externalContext.getSessionMap();
+                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);
+            }
+            return sequence;
+        }
+
+        @Override
+        public byte[] generateKey(FacesContext facesContext)
+        {
+            byte[] array = new byte[length];
+            byte[] key = new byte[length+4];
+            
+            //sessionIdGenerator.getRandomBytes(array);
+            random.nextBytes(array);
+            for (int i = 0; i < array.length; i++)
+            {
+                key[i] = array[i];
+            }
+            int value = generateCounterKey(facesContext);
+            key[array.length] =  (byte) (value >>> 24);
+            key[array.length+1] =  (byte) (value >>> 16);
+            key[array.length+2] =  (byte) (value >>> 8);
+            key[array.length+3] =  (byte) (value);
+
+            return key;
+        }
+
+        @Override
+        public String encode(byte[] key)
+        {
+            return new String(Hex.encodeHex(key));
+        }
+        
+        @Override
+        public byte[] decode(String value)
+        {
+            try
+            {
+                return Hex.decodeHex(value.toCharArray());
+            }
+            catch (DecoderException ex)
+            {
+                // Cannot decode, ignore silently, later it will be handled as
+                // ViewExpiredException
+            }
+            return null;
+        }
+    }
+    
+    /**
+     * 
+     * @param <T>
+     * @param <K>
+     * @param <V> 
+     */
+    protected abstract static class SessionViewStorageFactory <T extends KeyFactory<K,V>, K, V >
+    {
+        private KeyFactory<K, V> keyFactory;
+        
+        public SessionViewStorageFactory(KeyFactory<K, V> keyFactory)
+        {
+            this.keyFactory = keyFactory;
+        }
+        
+        public KeyFactory<K, V> getKeyFactory()
+        {
+            return keyFactory;
+        }
+        
+        public abstract SerializedViewCollection createSerializedViewCollection(
+                FacesContext context);
+        
+        public abstract SerializedViewKey createSerializedViewKey(
+                FacesContext facesContext, String viewId, K key);
+        
+    }
+    
+    private static class CounterSessionViewStorageFactory 
+        extends SessionViewStorageFactory <KeyFactory <Integer,String>, Integer, String>
+    {
+        public CounterSessionViewStorageFactory(KeyFactory<Integer, String> keyFactory)
+        {
+            super(keyFactory);
+        }
+
+        @Override
+        public SerializedViewCollection createSerializedViewCollection(
+                FacesContext context)
+        {
+            return new SerializedViewCollection();
+        }
+
+        @Override
+        public SerializedViewKey createSerializedViewKey(
+                FacesContext context, String viewId, Integer key)
+        {
+            if (context.isProjectStage(ProjectStage.Production))
+            {
+                return new IntIntSerializedViewKey(viewId.hashCode(), key);
+            }
+            else
+            {
+                return new ReferenceSerializedViewKey(viewId, key);
+            }
+        }
+    }
+    
+    private static class RandomSessionViewStorageFactory
+        extends SessionViewStorageFactory <KeyFactory <byte[],String>, byte[], String>
+    {
+        public RandomSessionViewStorageFactory(KeyFactory<byte[], String> keyFactory)
+        {
+            super(keyFactory);
+        }
+
+        @Override
+        public SerializedViewCollection createSerializedViewCollection(
+                FacesContext context)
+        {
+            return new SerializedViewCollection();
+        }
+
+        @Override
+        public SerializedViewKey createSerializedViewKey(
+                FacesContext context, String viewId, byte[] key)
+        {
+            if (context.isProjectStage(ProjectStage.Production))
+            {
+                return new IntByteArraySerializedViewKey(viewId.hashCode(), key);
+            }
+            else
+            {
+                return new ReferenceSerializedViewKey(viewId, key);
+            }
+        }
+    }
 }



Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Leonardo Uribe <lu...@gmail.com>.
2012/11/14 Leonardo Uribe <lu...@gmail.com>:
> 2012/11/14 Mark Struberg <st...@yahoo.de>:
>>> hat the hashCode could be the same is astronomical.
>>
>> I thought so the same, but Udo did hit that in production. This really happens!
>> And I really don't care about storing 20 bytes more because the encryption which is done immediately afterwards will use much more memory.
>>
>
> But I care about have the minimal possible size in the session. Every
> small improvement counts (many small improvements counts as a big
> one).
>
>>
>> Again: if the viewId would not needed for uniqueness, then we could also drop it completely.
>>
>
> Yes, that's true, I have told you that already. It doesn't matter, we
> can drop it completely. It is there just to provide some extra bytes
> in the key. It is there just by historical reasons. I have made a lot
> of reviews and fixes in that algorithm over the time. For example take
> a look at how Mojarra does it (just create a page and see what's in
> javax.faces.ViewState field). They don't store the viewId, and instead
> they have an option to use a counter or a random number.
>

Take a look at:

http://docs.jboss.org/jbossas/6/JSF_Guide/en-US/html/jsf.reference.html

com.sun.faces. generateUniqueServerStateIds

If true, generate random server state Ids. If false, create Ids sequentially.

>>
>> LieGrue,
>> strub
>>
>>
>>
>> ----- Original Message -----
>>> From: Leonardo Uribe <lu...@gmail.com>
>>> To: MyFaces Development <de...@myfaces.apache.org>; Mark Struberg <st...@yahoo.de>
>>> Cc:
>>> Sent: Wednesday, November 14, 2012 11:50 PM
>>> Subject: Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/
>>>
>>> 2012/11/14 Mark Struberg <st...@yahoo.de>:
>>>>
>>>>
>>>>
>>>>
>>>>  Leo we HAD that already in production (with an IBM JVM). Does that count?
>>>>
>>>>  using the hashCode to speed up caches is perfectly fine. But only for
>>> _excluding_ matches, Getting the same hashCode doesn't make sure something
>>> is unique.
>>>>
>>>>  Also in the private mail you pointed to an example yourself [1]:
>>>>
>>>>
>>>>  [1] pry(main)> "a".hash
>>>>  => 100 [2] pry(main)> "\0a".hash
>>>>  => 100 [3] pry(main)> "\0\0a".hash
>>>>  => 100 [4] pry(main)> "\0\0\0a".hash
>>>>  => 100 [5] pry(main)> "\0\0\0\0a".hash
>>>>  => 100 [6] pry(main)>
>>> "\0\0\0\0\0a".hash
>>>>  => 100
>>>>
>>>
>>> but you cannot put a \0 in a file name, because it is an invalid character
>>> for a file name, right? We are looking for REAL file names that can result in
>>> a viewId. For example:
>>>
>>> /home.xhtml
>>> /module/page.xhtml
>>>
>>> and so on. In practice, the probability of have two REAL pages that derives a
>>> viewId and that the hashCode could be the same is astronomical.
>>>
>>>>  It's just not guaranteed.
>>>>
>>>>  LieGrue,
>>>>  strub
>>>>
>>>>
>>>>
>>>>  [1]
>>> http://martin.kleppmann.com/2012/06/18/java-hashcode-unsafe-for-distributed-systems.html
>>>>
>>>>
>>>>
>>>>  ----- Original Message -----
>>>>>  From: Leonardo Uribe <lu...@gmail.com>
>>>>>  To: MyFaces Development <de...@myfaces.apache.org>; Mark Struberg
>>> <st...@yahoo.de>
>>>>>  Cc:
>>>>>  Sent: Wednesday, November 14, 2012 11:34 PM
>>>>>  Subject: Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./
>>> src/main/java/org/apache/myfaces/renderkit/
>>>>>
>>>>>  2012/11/14 Leonardo Uribe <lu...@gmail.com>:
>>>>>>   Hi
>>>>>>
>>>>>>   2012/11/14 Mark Struberg <st...@yahoo.de>:
>>>>>>>   Leo, there was a reason I removed it.
>>>>>>>
>>>>>>>
>>>>>>>   Even after discussing this over 10 mails in a private thread
>>> you
>>>>>  don't get it it seems. I will open a VOTE about principal design
>>>>>  fundamentals and we will act according to this.
>>>>>>>
>>>>>>>   Just you be prepated: A HASH IS NOT UNIQUE!
>>>>>>>
>>>>>>
>>>>>>   But I have told you multiple times, the algorithm does not rely on
>>> the
>>>>>>   hash to be unique, relies on the counter.
>>>>>>
>>>>>>>   Also saying in the mails you understand and then doing the
>>> same crazy
>>>>>  code again is just plain ******
>>>>>>>
>>>>>>>   I gonna revert it now and will write up the VOTE
>>>>>>
>>>>>>   The best way to resolve this is putting the arguments on the table
>>> and
>>>>>>   vote over that, right? after the vote we can do the necessary
>>> changes
>>>>>>   over the code. I have committed the fix that I suppose is correct.
>>>>>>
>>>>>
>>>>>  It is more, could you please try if the fix proposed by me works in
>>> your case?
>>>>>  could you please show two viewIds that can be written as valid file
>>> names that
>>>>>  has the same hashCode? I'm open to change my mind, but first I need
>>>>>  concrete arguments to do that.
>>>>>
>>>>>>   regards,
>>>>>>
>>>>>>   Leonardo
>>>>>>
>>>>>>>
>>>>>>>   LieGrue,
>>>>>>>   strub
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>   ----- Original Message -----
>>>>>>>>   From: "lu4242@apache.org"
>>> <lu...@apache.org>
>>>>>>>>   To: commits@myfaces.apache.org
>>>>>>>>   Cc:
>>>>>>>>   Sent: Wednesday, November 14, 2012 10:23 PM
>>>>>>>>   Subject: svn commit: r1409414 - in
>>> /myfaces/core/trunk/impl: ./
>>>>>  src/main/java/org/apache/myfaces/renderkit/
>>>>>>>>
>>>>>>>>   Author: lu4242
>>>>>>>>   Date: Wed Nov 14 21:23:35 2012
>>>>>>>>   New Revision: 1409414
>>>>>>>>
>>>>>>>>   URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
>>>>>>>>   Log:
>>>>>>>>   MYFACES-3638 revert commit 1408993 to include later
>>> solution
>>>>>  without
>>>>>>>>   refactoring.
>>>>>>>>
>>>>>>>>   Added:
>>>>>>>>
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>>>>>         - copied unchanged from r1408992,
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>>>>>   Removed:
>>>>>>>>
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
>>>>>>>>
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
>>>>>>>>
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
>>>>>>>>
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
>>>>>>>>
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
>>>>>>>>
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
>>>>>>>>   Modified:
>>>>>>>>       myfaces/core/trunk/impl/   (props changed)
>>>>>>>>
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>>>
>>>>>>>>   Propchange: myfaces/core/trunk/impl/
>>>>>>>>
>>>>>
>>> ------------------------------------------------------------------------------
>>>>>>>>   --- svn:ignore (original)
>>>>>>>>   +++ svn:ignore Wed Nov 14 21:23:35 2012
>>>>>>>>   @@ -7,7 +7,8 @@ target
>>>>>>>>   *.iml
>>>>>>>>   *.ipr
>>>>>>>>   *.iws
>>>>>>>>   -.idea
>>>>>>>>   .settings
>>>>>>>>   +
>>>>>>>>   cobertura.ser
>>>>>>>>   +
>>>>>>>>   test-output
>>>>>>>>
>>>>>>>>   Modified:
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>>>   URL:
>>>>>>>>
>>>>>
>>> http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
>>>>>>>>
>>>>>
>>> ==============================================================================
>>>>>>>>   ---
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>>>   (original)
>>>>>>>>   +++
>>>>>>>>
>>>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>>>   Wed Nov 14 21:23:35 2012
>>>>>>>>   @@ -30,16 +30,21 @@ import java.security.AccessController;
>>>>>>>>   import java.security.PrivilegedActionException;
>>>>>>>>   import java.security.PrivilegedExceptionAction;
>>>>>>>>   import java.util.ArrayList;
>>>>>>>>   +import java.util.Arrays;
>>>>>>>>   import java.util.HashMap;
>>>>>>>>   import java.util.List;
>>>>>>>>   import java.util.Map;
>>>>>>>>   +import java.util.Random;
>>>>>>>>   import java.util.logging.Level;
>>>>>>>>   import java.util.logging.Logger;
>>>>>>>>   import java.util.zip.GZIPInputStream;
>>>>>>>>   import java.util.zip.GZIPOutputStream;
>>>>>>>>   +import javax.faces.application.ProjectStage;
>>>>>>>>
>>>>>>>>   import javax.faces.context.ExternalContext;
>>>>>>>>   import javax.faces.context.FacesContext;
>>>>>>>>   +import org.apache.commons.codec.DecoderException;
>>>>>>>>   +import org.apache.commons.codec.binary.Hex;
>>>>>>>>
>>>>>>>>   import
>>> org.apache.commons.collections.map.AbstractReferenceMap;
>>>>>>>>   import org.apache.commons.collections.map.ReferenceMap;
>>>>>>>>   @@ -52,22 +57,22 @@ import
>>> org.apache.myfaces.shared.util.We
>>>>>>>>   class ServerSideStateCacheImpl extends
>>> StateCache<Object,
>>>>>  Object>
>>>>>>>>   {
>>>>>>>>        private static final Logger log =
>>>>>>>>
>>> Logger.getLogger(ServerSideStateCacheImpl.class.getName());
>>>>>>>>   -
>>>>>>>>   -    private static final String
>>> SERIALIZED_VIEW_SESSION_ATTR=
>>>>>>>>   +
>>>>>>>>   +    private static final String
>>> SERIALIZED_VIEW_SESSION_ATTR=
>>>>>>>>            ServerSideStateCacheImpl.class.getName() +
>>>>>>>>   ".SERIALIZED_VIEW";
>>>>>>>>   -
>>>>>>>>   -    private static final String
>>>>>  RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>>>>>>   +
>>>>>>>>   +    private static final String
>>>>>  RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>>>>>>            ServerSideStateCacheImpl.class.getName() +
>>>>>>>>   ".RESTORED_SERIALIZED_VIEW";
>>>>>>>>
>>>>>>>>   -    private static final String
>>> RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>>>>>   +    private static final String
>>> RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>>>>>            ServerSideStateCacheImpl.class.getName() +
>>>>>>>>   ".RESTORED_VIEW_KEY";
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        /**
>>>>>>>>         * Defines the amount (default = 20) of the latest
>>> views are
>>>>>  stored in
>>>>>>>>   session.
>>>>>>>>   -     *
>>>>>>>>   +     *
>>>>>>>>         * <p>Only applicable if state saving method is
>>>>>  "server" (=
>>>>>>>>   default).
>>>>>>>>         * </p>
>>>>>>>>   -     *
>>>>>>>>   +     *
>>>>>>>>         */
>>>>>>>>
>>>>>  @JSFWebConfigParam(defaultValue="20",since="1.1",
>>>>>>>>   classType="java.lang.Integer",
>>> group="state",
>>>>>>>>   tags="performance")
>>>>>>>>        private static final String
>>> NUMBER_OF_VIEWS_IN_SESSION_PARAM =
>>>>>>>>   "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
>>>>>>>>   @@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
>>>>>>>>        /**
>>>>>>>>         * 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>Only applicable if state saving method is
>>>>>  "server" (=
>>>>>>>>   default). For example, if this param has value = 2 and
>>>>>>>>   +     *
>>>>>>>>   +     * <p>Only applicable if state saving method is
>>>>>  "server" (=
>>>>>>>>   default). 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
>>>>>>>>   @@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>        @JSFWebConfigParam(since="2.0.6",
>>>>>>>>   classType="java.lang.Integer",
>>> group="state",
>>>>>>>>   tags="performance")
>>>>>>>>        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;
>>>>>>>>
>>>>>>>>        /**
>>>>>>>>   -     * Indicate if the state should be serialized before
>>> save it
>>>>>  on the
>>>>>>>>   session.
>>>>>>>>   +     * Indicate if the state should be serialized before
>>> save it
>>>>>  on the
>>>>>>>>   session.
>>>>>>>>         * <p>
>>>>>>>>         * 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.
>>>>>>>>   @@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>
>>>>>>>>        /**
>>>>>>>>         * Indicates that the serialized state will be
>>> compressed
>>>>>  before it is
>>>>>>>>   written to the session. By default true.
>>>>>>>>   -     *
>>>>>>>>   +     *
>>>>>>>>         * 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.
>>>>>>>>   @@ -140,38 +145,38 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>         * <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>
>>>>>>>>   +     * <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",
>>>>>  group="state",
>>>>>>>>   tags="performance")
>>>>>>>>        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
>>>>>>>>   +     * 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";
>>>>>>>>
>>>>>>>>        /**
>>>>>>>>         * 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.
>>>>>>>>   -     *
>>>>>>>>   +     *
>>>>>>>>         * <p>
>>>>>>>>         * Only applicable if state saving method is
>>>>>  "server" (=
>>>>>>>>   default).
>>>>>>>>         * The default value is false.</p>
>>>>>>>>   @@ -183,84 +188,90 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>        private static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE =
>>>>>>>>   "none";
>>>>>>>>        private static final String
>>>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM =
>>>>>  "secureRandom";
>>>>>>>>        private static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM =
>>>>>>>>   "random";
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        /**
>>>>>>>>         * Adds a random key to the generated view state
>>> session
>>>>>  token.
>>>>>>>>         */
>>>>>>>>   -    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>>   expectedValues="secureRandom, random, none",
>>>>>>>>   +    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>>   expectedValues="secureRandom, random, none",
>>>>>>>>                defaultValue="none",
>>>>>  group="state")
>>>>>>>>        private static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
>>>>>>>>                =
>>>>>>>>
>>>>>  "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
>>>>>>>>   -    private static final String
>>>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>>>>>   +    private static final String
>>>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>>>>>                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
>>>>>>>>
>>>>>>>>        /**
>>>>>>>>         * Set the default length of the random key added to
>>> the view
>>>>>  state session
>>>>>>>>   token.
>>>>>>>>   -     * By default is 8.
>>>>>>>>   +     * By default is 8.
>>>>>>>>         */
>>>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>>   defaultValue="8", group="state")
>>>>>>>>   -    static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>>>>>   +    private static final String
>>>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>>>>>                =
>>>>>>>>
>>>>>
>>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
>>>>>>>>   -    static final int
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>>>>>   +    private static final int
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>>>>>
>>>>>>>>        /**
>>>>>>>>   -     * Sets the random class to initialize the secure
>>> random id
>>>>>  generator.
>>>>>>>>   +     * Sets the random class to initialize the secure
>>> random id
>>>>>  generator.
>>>>>>>>         * By default it uses java.security.SecureRandom
>>>>>>>>         */
>>>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>>   group="state")
>>>>>>>>   -    static final String
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>>>>>   +    private static final String
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>>>>>                =
>>>>>>>>
>>>>>
>>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        /**
>>>>>>>>         * Sets the random provider to initialize the secure
>>> random id
>>>>>  generator.
>>>>>>>>         */
>>>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>>   group="state")
>>>>>>>>   -    static final String
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>>>>>   +    private static final String
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>>>>>                =
>>>>>>>>
>>>>>
>>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        /**
>>>>>>>>   -     * Sets the random algorithm to initialize the secure
>>> random
>>>>>  id generator.
>>>>>>>>   +     * Sets the random algorithm to initialize the secure
>>> random
>>>>>  id generator.
>>>>>>>>         * By default is SHA1PRNG
>>>>>>>>         */
>>>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>>   defaultValue="SHA1PRNG",
>>> group="state")
>>>>>>>>   -    static final String
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>>>>>   +    private static final String
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>>>>>                =
>>>>>>>>
>>>>>
>>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
>>>>>>>>   -
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>   +
>>>>>>>>        private static final int UNCOMPRESSED_FLAG = 0;
>>>>>>>>        private static final int COMPRESSED_FLAG = 1;
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        private static final Object[] EMPTY_STATES = new
>>>>>  Object[]{null, null};
>>>>>>>>
>>>>>>>>   +    //private static final int JSF_SEQUENCE_INDEX = 0;
>>>>>>>>   +
>>>>>>>>        private Boolean _useFlashScopePurgeViewsInSession =
>>> null;
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        private Integer _numberOfSequentialViewsInSession =
>>> null;
>>>>>>>>        private boolean _numberOfSequentialViewsInSessionSet
>>> = false;
>>>>>>>>
>>>>>>>>   +    //private final KeyFactory keyFactory;
>>>>>>>>        private SessionViewStorageFactory
>>> sessionViewStorageFactory;
>>>>>>>>
>>>>>>>>        public ServerSideStateCacheImpl()
>>>>>>>>        {
>>>>>>>>            FacesContext facesContext =
>>>>>  FacesContext.getCurrentInstance();
>>>>>>>>            String randomMode =
>>>>>>>>
>>>>>
>>> WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
>>>>>>>>   -
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>>>>>   +
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>>>>>
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
>>>>>>>>            if
>>>>>>>>
>>>>>
>>> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
>>>>>>>>            {
>>>>>>>>   -            sessionViewStorageFactory = new
>>>>>  SessionViewStorageFactory(
>>>>>>>>   +            //keyFactory = new
>>>>>  SecureRandomKeyFactory(facesContext);
>>>>>>>>   +            sessionViewStorageFactory = new
>>>>>  RandomSessionViewStorageFactory(
>>>>>>>>                        new
>>> SecureRandomKeyFactory(facesContext));
>>>>>>>>            }
>>>>>>>>            else if
>>>>>>>>
>>> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
>>>>>>>>            {
>>>>>>>>   -            sessionViewStorageFactory = new
>>>>>  SessionViewStorageFactory(
>>>>>>>>   +            //keyFactory = new
>>> RandomKeyFactory(facesContext);
>>>>>>>>   +            sessionViewStorageFactory = new
>>>>>  RandomSessionViewStorageFactory(
>>>>>>>>                        new RandomKeyFactory(facesContext));
>>>>>>>>            }
>>>>>>>>            else
>>>>>>>>            {
>>>>>>>>   -            sessionViewStorageFactory = new
>>>>>  SessionViewStorageFactory(new
>>>>>>>>   CounterKeyFactory());
>>>>>>>>   +            //keyFactory = new CounterKeyFactory();
>>>>>>>>   +            sessionViewStorageFactory = new
>>>>>>>>   CounterSessionViewStorageFactory(new CounterKeyFactory());
>>>>>>>>            }
>>>>>>>>        }
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        //------------------------------------- METHODS
>>> COPIED FROM
>>>>>>>>   JspStateManagerImpl--------------------------------
>>>>>>>>
>>>>>>>>        protected Object getServerStateId(FacesContext
>>> facesContext,
>>>>>  Object state)
>>>>>>>>   @@ -285,16 +296,16 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>            }
>>>>>>>>
>>>>>>>>            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())
>>>>>  &&
>>>>>>>>   +                if
>>>>>>>>
>>> (isUseFlashScopePurgeViewsInSession(context.getExternalContext())
>>>>>  &&
>>>>>>>>
>>>>>>>>
>>> Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
>>>>>>>>
>>>>>>>>   .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
>>>>>>>>                    {
>>>>>>>>   @@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                    }
>>>>>>>>                }
>>>>>>>>            }
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>            SerializedViewKey nextKey =
>>>>>>>>   getSessionViewStorageFactory().createSerializedViewKey(
>>>>>>>>                    context,
>>> context.getViewRoot().getViewId(),
>>>>>>>>   getNextViewSequence(context));
>>>>>>>>            viewCollection.add(context,
>>> serializeView(context,
>>>>>  serializedView),
>>>>>>>>   nextKey, key);
>>>>>>>>   @@ -339,14 +350,14 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>                    }
>>>>>>>>                }
>>>>>>>>
>>>>>  attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR,
>>>>>>>>   serializedView);
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>                if
>>>>>  (getNumberOfSequentialViewsInSession(externalContext) != null
>>>>>>>>   &&
>>>>>>>>
>>>>>  getNumberOfSequentialViewsInSession(externalContext) > 0)
>>>>>>>>                {
>>>>>>>>                    SerializedViewKey key =
>>>>>  getSessionViewStorageFactory().
>>>>>>>>                            createSerializedViewKey(context,
>>> viewId,
>>>>>  sequence);
>>>>>>>>
>>> attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR,
>>>>>  key);
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>                    if
>>>>>  (isUseFlashScopePurgeViewsInSession(externalContext))
>>>>>>>>                    {
>>>>>>>>
>>>>>>>>
>>> externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR,
>>>>>  key);
>>>>>>>>   @@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                    //Object[] stateArray = (Object[])
>>> serializedView;
>>>>>>>>
>>>>>>>>                    ObjectOutputStream out = new
>>>>>  ObjectOutputStream(os);
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>                    out.writeObject(serializedView);
>>>>>>>>                    //out.writeObject(stateArray[0]);
>>>>>>>>                    //out.writeObject(stateArray[1]);
>>>>>>>>   @@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                        final ObjectInputStream in = new
>>>>>>>>   MyFacesObjectInputStream(is);
>>>>>>>>                        ois = in;
>>>>>>>>                        Object object = null;
>>>>>>>>   -                    if (System.getSecurityManager() !=
>>> null)
>>>>>>>>   +                    if (System.getSecurityManager() !=
>>> null)
>>>>>>>>                        {
>>>>>>>>   -                        object =
>>> AccessController.doPrivileged(new
>>>>>>>>   PrivilegedExceptionAction<Object>()
>>>>>>>>   +                        object =
>>> AccessController.doPrivileged(new
>>>>>>>>   PrivilegedExceptionAction<Object>()
>>>>>>>>                            {
>>>>>>>>                                public Object run() throws
>>>>>>>>   PrivilegedActionException, IOException,
>>> ClassNotFoundException
>>>>>>>>                                {
>>>>>>>>   @@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                        }
>>>>>>>>                    }
>>>>>>>>                }
>>>>>>>>   -            catch (PrivilegedActionException e)
>>>>>>>>   +            catch (PrivilegedActionException e)
>>>>>>>>                {
>>>>>>>>                    log.log(Level.SEVERE, "Exiting
>>>>>  deserializeView - Could not
>>>>>>>>   deserialize state: " + e.getMessage(), e);
>>>>>>>>                    return null;
>>>>>>>>   @@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                return null;
>>>>>>>>            }
>>>>>>>>        }
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        protected static class SerializedViewCollection
>>> implements
>>>>>  Serializable
>>>>>>>>        {
>>>>>>>>            private static final long serialVersionUID =
>>>>>  -3734849062185115847L;
>>>>>>>>   @@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>            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 =
>>>>>>>>   +
>>>>>>>>   +        private final Map<SerializedViewKey,
>>>>>  SerializedViewKey>
>>>>>>>>   _precedence =
>>>>>>>>                new HashMap<SerializedViewKey,
>>>>>  SerializedViewKey>();
>>>>>>>>
>>>>>>>>            // old views will be hold as soft references
>>> which will be
>>>>>  removed by
>>>>>>>>   @@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                    // into the map.
>>>>>>>>                    state = null;
>>>>>>>>                }
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>                Integer maxCount =
>>>>>  getNumberOfSequentialViewsInSession(context);
>>>>>>>>                if (maxCount != null)
>>>>>>>>                {
>>>>>>>>   @@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                      previousKey =
>>> _precedence.get(previousKey);
>>>>>>>>                      count++;
>>>>>>>>                    } while (previousKey != null &&
>>> count <
>>>>>  maxCount);
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>                    if (previousKey != null)
>>>>>>>>                    {
>>>>>>>>                        SerializedViewKey keyToRemove =
>>>>>  (SerializedViewKey)
>>>>>>>>   previousKey;
>>>>>>>>   @@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                            {
>>>>>>>>
>>> _serializedViews.remove(keyToRemove);
>>>>>>>>                            }
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>                            keyToRemove =
>>>>>  _precedence.remove(keyToRemove);
>>>>>>>>                        }  while(keyToRemove != null);
>>>>>>>>                    }
>>>>>>>>   @@ -680,11 +691,11 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>                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,
>>>>>>>>   +                    // 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
>>>>>>>>   @@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                    if (_serializedViews.containsKey(key)
>>> &&
>>>>>>>>
>>>>>>>>
>>>>>
>>> !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
>>>>>>>>                    {
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>                        getOldSerializedViewsMap().put(key,
>>>>>>>>   _serializedViews.remove(key));
>>>>>>>>                    }
>>>>>>>>                    else
>>>>>>>>   @@ -708,10 +719,10 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>
>>>>>>>>            protected Integer
>>>>>  getNumberOfSequentialViewsInSession(FacesContext
>>>>>>>>   context)
>>>>>>>>            {
>>>>>>>>   -            return
>>>>>>>>
>>>>>
>>> WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
>>>>>>>>   +            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
>>>>>>>>   @@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                FacesContext context =
>>>>>  FacesContext.getCurrentInstance();
>>>>>>>>                if (_oldSerializedViews == null &&
>>> context !=
>>>>>  null)
>>>>>>>>                {
>>>>>>>>   -                String cacheMode =
>>>>>  getCacheOldViewsInSessionMode(context);
>>>>>>>>   +                String cacheMode =
>>>>>  getCacheOldViewsInSessionMode(context);
>>>>>>>>                    if
>>>>>  (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
>>>>>>>>                    {
>>>>>>>>                        _oldSerializedViews = new
>>>>>>>>   ReferenceMap(AbstractReferenceMap.WEAK,
>>> AbstractReferenceMap.WEAK,
>>>>>  true);
>>>>>>>>   @@ -773,13 +784,13 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>                        _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
>>>>>>>>   @@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                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;
>>>>>>>>   @@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends
>>> S
>>>>>>>>                    return
>>> CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
>>>>>>>>                }
>>>>>>>>            }
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>            public Object get(SerializedViewKey key)
>>>>>>>>            {
>>>>>>>>                Object value = _serializedViews.get(key);
>>>>>>>>   @@ -846,7 +857,172 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>            }
>>>>>>>>        }
>>>>>>>>
>>>>>>>>   +    /**
>>>>>>>>   +     * Base implementation where all keys used to
>>> identify the
>>>>>  state of a view
>>>>>>>>   should
>>>>>>>>   +     * extend.
>>>>>>>>   +     */
>>>>>>>>   +    protected abstract static class SerializedViewKey
>>> implements
>>>>>  Serializable
>>>>>>>>   +    {
>>>>>>>>   +    }
>>>>>>>>   +
>>>>>>>>   +    /**
>>>>>>>>   +     * Implementation of SerializedViewKey, where the
>>> hashCode of
>>>>>  the viewId is
>>>>>>>>   used
>>>>>>>>   +     * and the sequenceId is a numeric value.
>>>>>>>>   +     */
>>>>>>>>   +    private static class IntIntSerializedViewKey extends
>>>>>  SerializedViewKey
>>>>>>>>   +        implements Serializable
>>>>>>>>   +    {
>>>>>>>>   +        private static final long serialVersionUID =
>>>>>  -1170697124386063642L;
>>>>>>>>   +
>>>>>>>>   +        private final int _viewId;
>>>>>>>>   +        private final int _sequenceId;
>>>>>>>>   +
>>>>>>>>   +        public IntIntSerializedViewKey(int viewId, int
>>> sequence)
>>>>>>>>   +        {
>>>>>>>>   +            _sequenceId = sequence;
>>>>>>>>   +            _viewId = viewId;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public boolean equals(Object obj)
>>>>>>>>   +        {
>>>>>>>>   +            if (obj == null)
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            if (getClass() != obj.getClass())
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            final IntIntSerializedViewKey other =
>>>>>  (IntIntSerializedViewKey)
>>>>>>>>   obj;
>>>>>>>>   +            if (this._viewId != other._viewId)
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            if (this._sequenceId != other._sequenceId)
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            return true;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public int hashCode()
>>>>>>>>   +        {
>>>>>>>>   +            int hash = 7;
>>>>>>>>   +            hash = 83 * hash + this._viewId;
>>>>>>>>   +            hash = 83 * hash + this._sequenceId;
>>>>>>>>   +            return hash;
>>>>>>>>   +        }
>>>>>>>>   +    }
>>>>>>>>   +
>>>>>>>>   +    /**
>>>>>>>>   +     * Implementation of SerializedViewKey, where the
>>> hashCode of
>>>>>  the viewId is
>>>>>>>>   used
>>>>>>>>   +     * and the sequenceId is a string value.
>>>>>>>>   +     */
>>>>>>>>   +    private static class IntByteArraySerializedViewKey
>>> extends
>>>>>>>>   SerializedViewKey
>>>>>>>>   +        implements Serializable
>>>>>>>>   +    {
>>>>>>>>   +        private final int _viewId;
>>>>>>>>   +        private final byte[] _sequenceId;
>>>>>>>>   +
>>>>>>>>   +        public IntByteArraySerializedViewKey(int viewId,
>>> byte[]
>>>>>  sequence)
>>>>>>>>   +        {
>>>>>>>>   +            _sequenceId = sequence;
>>>>>>>>   +            _viewId = viewId;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public boolean equals(Object obj)
>>>>>>>>   +        {
>>>>>>>>   +            if (obj == null)
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            if (getClass() != obj.getClass())
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            final IntByteArraySerializedViewKey other =
>>>>>>>>   (IntByteArraySerializedViewKey) obj;
>>>>>>>>   +            if (this._viewId != other._viewId)
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            if (!Arrays.equals(this._sequenceId,
>>>>>  other._sequenceId))
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            return true;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public int hashCode()
>>>>>>>>   +        {
>>>>>>>>   +            int hash = 5;
>>>>>>>>   +            hash = 37 * hash + this._viewId;
>>>>>>>>   +            hash = 37 * hash +
>>> Arrays.hashCode(this._sequenceId);
>>>>>>>>   +            return hash;
>>>>>>>>   +        }
>>>>>>>>   +    }
>>>>>>>>   +
>>>>>>>>   +
>>>>>>>>   +    /**
>>>>>>>>   +     * Implementation of SerializedViewKey, where the
>>> viewId and
>>>>>  the sequenceId
>>>>>>>>   can be
>>>>>>>>   +     * anything.
>>>>>>>>   +     */
>>>>>>>>   +    private static class
>>> ReferenceSerializedViewKey<I,K>
>>>>>  extends
>>>>>>>>   SerializedViewKey
>>>>>>>>   +        implements Serializable
>>>>>>>>   +    {
>>>>>>>>   +        private static final long serialVersionUID =
>>>>>  -1170697124386063642L;
>>>>>>>>   +
>>>>>>>>   +        private final I _viewId;
>>>>>>>>   +        private final K _sequenceId;
>>>>>>>>
>>>>>>>>   +        public ReferenceSerializedViewKey()
>>>>>>>>   +        {
>>>>>>>>   +            _sequenceId = null;
>>>>>>>>   +            _viewId = null;
>>>>>>>>   +        }
>>>>>>>>   +        public ReferenceSerializedViewKey(I viewId, K
>>> sequence)
>>>>>>>>   +        {
>>>>>>>>   +            _sequenceId = sequence;
>>>>>>>>   +            _viewId = viewId;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public boolean equals(Object obj)
>>>>>>>>   +        {
>>>>>>>>   +            if (obj == null)
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            if (getClass() != obj.getClass())
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            final ReferenceSerializedViewKey<I, K>
>>> other =
>>>>>>>>   (ReferenceSerializedViewKey<I, K>) obj;
>>>>>>>>   +            if (this._viewId != other._viewId &&
>>>>>  (this._viewId == null
>>>>>>>>   || !this._viewId.equals(other._viewId)))
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            if (this._sequenceId != other._sequenceId
>>> &&
>>>>>>>>   +                (this._sequenceId == null ||
>>>>>>>>   !this._sequenceId.equals(other._sequenceId)))
>>>>>>>>   +            {
>>>>>>>>   +                return false;
>>>>>>>>   +            }
>>>>>>>>   +            return true;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public int hashCode()
>>>>>>>>   +        {
>>>>>>>>   +            int hash = 7;
>>>>>>>>   +            hash = 83 * hash + (this._viewId != null ?
>>>>>  this._viewId.hashCode()
>>>>>>>>   : 0);
>>>>>>>>   +            hash = 83 * hash + (this._sequenceId != null
>>> ?
>>>>>>>>   this._sequenceId.hashCode() : 0);
>>>>>>>>   +            return hash;
>>>>>>>>   +        }
>>>>>>>>   +    }
>>>>>>>>   +
>>>>>>>>        //------------------------------------- METHOD FROM
>>> StateCache
>>>>>>>>   ------------------------------------------------
>>>>>>>>
>>>>>>>>        @Override
>>>>>>>>   @@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>            }
>>>>>>>>            //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);
>>>>>>>>        }
>>>>>>>>
>>>>>>>>   @@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>        {
>>>>>>>>            return
>>>>>>>>
>>>>>  getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
>>>>>>>>        }
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        @Override
>>>>>>>>        public boolean
>>>>>  isWriteStateAfterRenderViewRequired(FacesContext
>>>>>>>>   facesContext)
>>>>>>>>        {
>>>>>>>>   @@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>        }
>>>>>>>>
>>>>>>>>        //------------------------------------- Custom
>>> methods
>>>>>>>>   -----------------------------------------------------
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        private boolean
>>>>>  isUseFlashScopePurgeViewsInSession(ExternalContext
>>>>>>>>   externalContext)
>>>>>>>>        {
>>>>>>>>            if (_useFlashScopePurgeViewsInSession == null)
>>>>>>>>   @@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl
>>> extends S
>>>>>>>>            }
>>>>>>>>            return _useFlashScopePurgeViewsInSession;
>>>>>>>>        }
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        private Integer
>>>>>  getNumberOfSequentialViewsInSession(ExternalContext
>>>>>>>>   externalContext)
>>>>>>>>        {
>>>>>>>>            if (!_numberOfSequentialViewsInSessionSet)
>>>>>>>>            {
>>>>>>>>                _numberOfSequentialViewsInSession =
>>>>>>>>   WebConfigParamUtils.getIntegerInitParameter(
>>>>>>>>   -                    externalContext,
>>>>>>>>   +                    externalContext,
>>>>>>>>
>>> NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
>>>>>>>>                _numberOfSequentialViewsInSessionSet = true;
>>>>>>>>            }
>>>>>>>>            return _numberOfSequentialViewsInSession;
>>>>>>>>        }
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        protected KeyFactory getKeyFactory(FacesContext
>>> facesContext)
>>>>>>>>        {
>>>>>>>>            //return keyFactory;
>>>>>>>>            return sessionViewStorageFactory.getKeyFactory();
>>>>>>>>        }
>>>>>>>>   -
>>>>>>>>   +
>>>>>>>>        protected SessionViewStorageFactory
>>>>>  getSessionViewStorageFactory()
>>>>>>>>        {
>>>>>>>>            return sessionViewStorageFactory;
>>>>>>>>        }
>>>>>>>>   +
>>>>>>>>
>>>>>>>>   +    protected abstract static class KeyFactory<K,
>>> V>
>>>>>>>>   +    {
>>>>>>>>   +
>>>>>>>>   +        /**
>>>>>>>>   +         * Generates a unique key per session
>>>>>>>>   +         *
>>>>>>>>   +         * @param facesContext
>>>>>>>>   +         * @return
>>>>>>>>   +         */
>>>>>>>>   +        public abstract K generateKey(FacesContext
>>> facesContext);
>>>>>>>>   +
>>>>>>>>   +        /**
>>>>>>>>   +         * Encode a Key into a value that will be used as
>>> view
>>>>>  state session
>>>>>>>>   token
>>>>>>>>   +         *
>>>>>>>>   +         * @param key
>>>>>>>>   +         * @return
>>>>>>>>   +         */
>>>>>>>>   +        public abstract V encode(K key);
>>>>>>>>
>>>>>>>>   +        /**
>>>>>>>>   +         * Decode a view state session token into a key
>>>>>>>>   +         *
>>>>>>>>   +         * @param value
>>>>>>>>   +         * @return
>>>>>>>>   +         */
>>>>>>>>   +        public abstract K decode(V value);
>>>>>>>>   +
>>>>>>>>   +    }
>>>>>>>>   +
>>>>>>>>   +    private static class CounterKeyFactory extends
>>>>>  KeyFactory<Integer,
>>>>>>>>   String>
>>>>>>>>   +    {
>>>>>>>>   +        /**
>>>>>>>>   +         * Take the counter from session scope and
>>> increment
>>>>>>>>   +         *
>>>>>>>>   +         * @param facesContext
>>>>>>>>   +         * @return
>>>>>>>>   +         */
>>>>>>>>   +        @Override
>>>>>>>>   +        public Integer generateKey(FacesContext
>>> facesContext)
>>>>>>>>   +        {
>>>>>>>>   +            ExternalContext externalContext =
>>>>>>>>   facesContext.getExternalContext();
>>>>>>>>   +            Object sessionObj =
>>> externalContext.getSession(true);
>>>>>>>>   +            Integer sequence = null;
>>>>>>>>   +            synchronized(sessionObj) // synchronized to
>>> increase
>>>>>  sequence if
>>>>>>>>   multiple requests
>>>>>>>>   +                                    // are handled at the
>>> same
>>>>>  time for the
>>>>>>>>   session
>>>>>>>>   +            {
>>>>>>>>   +                Map<String, Object> map =
>>>>>>>>   externalContext.getSessionMap();
>>>>>>>>   +                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);
>>>>>>>>   +            }
>>>>>>>>   +            return sequence;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        public String encode(Integer sequence)
>>>>>>>>   +        {
>>>>>>>>   +            return Integer.toString(sequence,
>>>>>  Character.MAX_RADIX);
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        public Integer decode(String serverStateId)
>>>>>>>>   +        {
>>>>>>>>   +             return Integer.valueOf((String)
>>> serverStateId,
>>>>>>>>   Character.MAX_RADIX);
>>>>>>>>   +        }
>>>>>>>>   +    }
>>>>>>>>   +
>>>>>>>>   +    /**
>>>>>>>>   +     * This factory generate a key composed by a counter
>>> and a
>>>>>  random number.
>>>>>>>>   The
>>>>>>>>   +     * counter ensures uniqueness, and the random number
>>> prevents
>>>>>  guess the
>>>>>>>>   next
>>>>>>>>   +     * session token.
>>>>>>>>   +     */
>>>>>>>>   +    private static class SecureRandomKeyFactory extends
>>>>>  KeyFactory<byte[],
>>>>>>>>   String>
>>>>>>>>   +    {
>>>>>>>>   +        private final SessionIdGenerator
>>> sessionIdGenerator;
>>>>>>>>   +        private final int length;
>>>>>>>>   +
>>>>>>>>   +        public SecureRandomKeyFactory(FacesContext
>>> facesContext)
>>>>>>>>   +        {
>>>>>>>>   +            length =
>>>>>>>>
>>>>>
>>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>>>>>   +
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>>>>>   +
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>>>>>   +            sessionIdGenerator = new
>>> SessionIdGenerator();
>>>>>>>>   +
>>> sessionIdGenerator.setSessionIdLength(length);
>>>>>>>>   +            String secureRandomClass =
>>>>>>>>   WebConfigParamUtils.getStringInitParameter(
>>>>>>>>   +                    facesContext.getExternalContext(),
>>>>>>>>   +
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
>>>>>>>>   +            if (secureRandomClass != null)
>>>>>>>>   +            {
>>>>>>>>   +
>>>>>  sessionIdGenerator.setSecureRandomClass(secureRandomClass);
>>>>>>>>   +            }
>>>>>>>>   +            String secureRandomProvider =
>>>>>>>>   WebConfigParamUtils.getStringInitParameter(
>>>>>>>>   +                    facesContext.getExternalContext(),
>>>>>>>>   +
>>>>>>>>
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
>>>>>>>>   +            if (secureRandomProvider != null)
>>>>>>>>   +            {
>>>>>>>>   +
>>>>>>>>
>>> sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
>>>>>>>>   +            }
>>>>>>>>   +            String secureRandomAlgorithm =
>>>>>>>>   WebConfigParamUtils.getStringInitParameter(
>>>>>>>>   +                    facesContext.getExternalContext(),
>>>>>>>>   +
>>>>>>>>
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
>>>>>>>>   +            if (secureRandomAlgorithm != null)
>>>>>>>>   +            {
>>>>>>>>   +
>>>>>>>>
>>> sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
>>>>>>>>   +            }
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        public Integer generateCounterKey(FacesContext
>>>>>  facesContext)
>>>>>>>>   +        {
>>>>>>>>   +            ExternalContext externalContext =
>>>>>>>>   facesContext.getExternalContext();
>>>>>>>>   +            Object sessionObj =
>>> externalContext.getSession(true);
>>>>>>>>   +            Integer sequence = null;
>>>>>>>>   +            synchronized(sessionObj) // synchronized to
>>> increase
>>>>>  sequence if
>>>>>>>>   multiple requests
>>>>>>>>   +                                    // are handled at the
>>> same
>>>>>  time for the
>>>>>>>>   session
>>>>>>>>   +            {
>>>>>>>>   +                Map<String, Object> map =
>>>>>>>>   externalContext.getSessionMap();
>>>>>>>>   +                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);
>>>>>>>>   +            }
>>>>>>>>   +            return sequence;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public byte[] generateKey(FacesContext
>>> facesContext)
>>>>>>>>   +        {
>>>>>>>>   +            byte[] array = new byte[length];
>>>>>>>>   +            byte[] key = new byte[length+4];
>>>>>>>>   +
>>>>>>>>   +            sessionIdGenerator.getRandomBytes(array);
>>>>>>>>   +            for (int i = 0; i < array.length; i++)
>>>>>>>>   +            {
>>>>>>>>   +                key[i] = array[i];
>>>>>>>>   +            }
>>>>>>>>   +            int value = generateCounterKey(facesContext);
>>>>>>>>   +            key[array.length] =  (byte) (value
>>>>>>  24);
>>>>>>>>   +            key[array.length+1] =  (byte) (value
>>>>>>  16);
>>>>>>>>   +            key[array.length+2] =  (byte) (value
>>>>>>  8);
>>>>>>>>   +            key[array.length+3] =  (byte) (value);
>>>>>>>>   +
>>>>>>>>   +            return key;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public String encode(byte[] key)
>>>>>>>>   +        {
>>>>>>>>   +            return new String(Hex.encodeHex(key));
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public byte[] decode(String value)
>>>>>>>>   +        {
>>>>>>>>   +            try
>>>>>>>>   +            {
>>>>>>>>   +                return
>>> Hex.decodeHex(value.toCharArray());
>>>>>>>>   +            }
>>>>>>>>   +            catch (DecoderException ex)
>>>>>>>>   +            {
>>>>>>>>   +                // Cannot decode, ignore silently, later
>>> it will
>>>>>  be handled as
>>>>>>>>   +                // ViewExpiredException
>>>>>>>>   +            }
>>>>>>>>   +            return null;
>>>>>>>>   +        }
>>>>>>>>   +    }
>>>>>>>>   +
>>>>>>>>   +    private static class RandomKeyFactory extends
>>>>>  KeyFactory<byte[],
>>>>>>>>   String>
>>>>>>>>   +    {
>>>>>>>>   +        private final Random random;
>>>>>>>>   +        private final int length;
>>>>>>>>   +
>>>>>>>>   +        public RandomKeyFactory(FacesContext
>>> facesContext)
>>>>>>>>   +        {
>>>>>>>>   +            length =
>>>>>>>>
>>>>>
>>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>>>>>   +
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>>>>>   +
>>>>>>>>
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>>>>>   +            random = new
>>>>>  Random(((int)System.nanoTime())+this.hashCode());
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        public Integer generateCounterKey(FacesContext
>>>>>  facesContext)
>>>>>>>>   +        {
>>>>>>>>   +            ExternalContext externalContext =
>>>>>>>>   facesContext.getExternalContext();
>>>>>>>>   +            Object sessionObj =
>>> externalContext.getSession(true);
>>>>>>>>   +            Integer sequence = null;
>>>>>>>>   +            synchronized(sessionObj) // synchronized to
>>> increase
>>>>>  sequence if
>>>>>>>>   multiple requests
>>>>>>>>   +                                    // are handled at the
>>> same
>>>>>  time for the
>>>>>>>>   session
>>>>>>>>   +            {
>>>>>>>>   +                Map<String, Object> map =
>>>>>>>>   externalContext.getSessionMap();
>>>>>>>>   +                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);
>>>>>>>>   +            }
>>>>>>>>   +            return sequence;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public byte[] generateKey(FacesContext
>>> facesContext)
>>>>>>>>   +        {
>>>>>>>>   +            byte[] array = new byte[length];
>>>>>>>>   +            byte[] key = new byte[length+4];
>>>>>>>>   +
>>>>>>>>   +            //sessionIdGenerator.getRandomBytes(array);
>>>>>>>>   +            random.nextBytes(array);
>>>>>>>>   +            for (int i = 0; i < array.length; i++)
>>>>>>>>   +            {
>>>>>>>>   +                key[i] = array[i];
>>>>>>>>   +            }
>>>>>>>>   +            int value = generateCounterKey(facesContext);
>>>>>>>>   +            key[array.length] =  (byte) (value
>>>>>>  24);
>>>>>>>>   +            key[array.length+1] =  (byte) (value
>>>>>>  16);
>>>>>>>>   +            key[array.length+2] =  (byte) (value
>>>>>>  8);
>>>>>>>>   +            key[array.length+3] =  (byte) (value);
>>>>>>>>   +
>>>>>>>>   +            return key;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public String encode(byte[] key)
>>>>>>>>   +        {
>>>>>>>>   +            return new String(Hex.encodeHex(key));
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public byte[] decode(String value)
>>>>>>>>   +        {
>>>>>>>>   +            try
>>>>>>>>   +            {
>>>>>>>>   +                return
>>> Hex.decodeHex(value.toCharArray());
>>>>>>>>   +            }
>>>>>>>>   +            catch (DecoderException ex)
>>>>>>>>   +            {
>>>>>>>>   +                // Cannot decode, ignore silently, later
>>> it will
>>>>>  be handled as
>>>>>>>>   +                // ViewExpiredException
>>>>>>>>   +            }
>>>>>>>>   +            return null;
>>>>>>>>   +        }
>>>>>>>>   +    }
>>>>>>>>   +
>>>>>>>>   +    /**
>>>>>>>>   +     *
>>>>>>>>   +     * @param <T>
>>>>>>>>   +     * @param <K>
>>>>>>>>   +     * @param <V>
>>>>>>>>   +     */
>>>>>>>>   +    protected abstract static class
>>> SessionViewStorageFactory
>>>>>  <T extends
>>>>>>>>   KeyFactory<K,V>, K, V >
>>>>>>>>   +    {
>>>>>>>>   +        private KeyFactory<K, V> keyFactory;
>>>>>>>>   +
>>>>>>>>   +        public SessionViewStorageFactory(KeyFactory<K,
>>> V>
>>>>>  keyFactory)
>>>>>>>>   +        {
>>>>>>>>   +            this.keyFactory = keyFactory;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        public KeyFactory<K, V> getKeyFactory()
>>>>>>>>   +        {
>>>>>>>>   +            return keyFactory;
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        public abstract SerializedViewCollection
>>>>>>>>   createSerializedViewCollection(
>>>>>>>>   +                FacesContext context);
>>>>>>>>   +
>>>>>>>>   +        public abstract SerializedViewKey
>>> createSerializedViewKey(
>>>>>>>>   +                FacesContext facesContext, String viewId,
>>> K key);
>>>>>>>>   +
>>>>>>>>   +    }
>>>>>>>>   +
>>>>>>>>   +    private static class CounterSessionViewStorageFactory
>>>>>>>>   +        extends SessionViewStorageFactory <KeyFactory
>>>>>>>>   <Integer,String>, Integer, String>
>>>>>>>>   +    {
>>>>>>>>   +        public
>>>>>  CounterSessionViewStorageFactory(KeyFactory<Integer,
>>>>>>>>   String> keyFactory)
>>>>>>>>   +        {
>>>>>>>>   +            super(keyFactory);
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public SerializedViewCollection
>>>>>  createSerializedViewCollection(
>>>>>>>>   +                FacesContext context)
>>>>>>>>   +        {
>>>>>>>>   +            return new SerializedViewCollection();
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public SerializedViewKey createSerializedViewKey(
>>>>>>>>   +                FacesContext context, String viewId,
>>> Integer key)
>>>>>>>>   +        {
>>>>>>>>   +            if
>>> (context.isProjectStage(ProjectStage.Production))
>>>>>>>>   +            {
>>>>>>>>   +                return new
>>>>>  IntIntSerializedViewKey(viewId.hashCode(), key);
>>>>>>>>   +            }
>>>>>>>>   +            else
>>>>>>>>   +            {
>>>>>>>>   +                return new
>>> ReferenceSerializedViewKey(viewId,
>>>>>  key);
>>>>>>>>   +            }
>>>>>>>>   +        }
>>>>>>>>   +    }
>>>>>>>>   +
>>>>>>>>   +    private static class RandomSessionViewStorageFactory
>>>>>>>>   +        extends SessionViewStorageFactory <KeyFactory
>>>>>  <byte[],String>,
>>>>>>>>   byte[], String>
>>>>>>>>   +    {
>>>>>>>>   +        public
>>>>>  RandomSessionViewStorageFactory(KeyFactory<byte[], String>
>>>>>>>>   keyFactory)
>>>>>>>>   +        {
>>>>>>>>   +            super(keyFactory);
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public SerializedViewCollection
>>>>>  createSerializedViewCollection(
>>>>>>>>   +                FacesContext context)
>>>>>>>>   +        {
>>>>>>>>   +            return new SerializedViewCollection();
>>>>>>>>   +        }
>>>>>>>>   +
>>>>>>>>   +        @Override
>>>>>>>>   +        public SerializedViewKey createSerializedViewKey(
>>>>>>>>   +                FacesContext context, String viewId,
>>> byte[] key)
>>>>>>>>   +        {
>>>>>>>>   +            if
>>> (context.isProjectStage(ProjectStage.Production))
>>>>>>>>   +            {
>>>>>>>>   +                return new
>>>>>  IntByteArraySerializedViewKey(viewId.hashCode(),
>>>>>>>>   key);
>>>>>>>>   +            }
>>>>>>>>   +            else
>>>>>>>>   +            {
>>>>>>>>   +                return new
>>> ReferenceSerializedViewKey(viewId,
>>>>>  key);
>>>>>>>>   +            }
>>>>>>>>   +        }
>>>>>>>>   +    }
>>>>>>>>   }
>>>>>>>>
>>>>>
>>>

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Leonardo Uribe <lu...@gmail.com>.
2012/11/14 Mark Struberg <st...@yahoo.de>:
>> hat the hashCode could be the same is astronomical.
>
> I thought so the same, but Udo did hit that in production. This really happens!
> And I really don't care about storing 20 bytes more because the encryption which is done immediately afterwards will use much more memory.
>

But I care about have the minimal possible size in the session. Every
small improvement counts (many small improvements counts as a big
one).

>
> Again: if the viewId would not needed for uniqueness, then we could also drop it completely.
>

Yes, that's true, I have told you that already. It doesn't matter, we
can drop it completely. It is there just to provide some extra bytes
in the key. It is there just by historical reasons. I have made a lot
of reviews and fixes in that algorithm over the time. For example take
a look at how Mojarra does it (just create a page and see what's in
javax.faces.ViewState field). They don't store the viewId, and instead
they have an option to use a counter or a random number.

>
> LieGrue,
> strub
>
>
>
> ----- Original Message -----
>> From: Leonardo Uribe <lu...@gmail.com>
>> To: MyFaces Development <de...@myfaces.apache.org>; Mark Struberg <st...@yahoo.de>
>> Cc:
>> Sent: Wednesday, November 14, 2012 11:50 PM
>> Subject: Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/
>>
>> 2012/11/14 Mark Struberg <st...@yahoo.de>:
>>>
>>>
>>>
>>>
>>>  Leo we HAD that already in production (with an IBM JVM). Does that count?
>>>
>>>  using the hashCode to speed up caches is perfectly fine. But only for
>> _excluding_ matches, Getting the same hashCode doesn't make sure something
>> is unique.
>>>
>>>  Also in the private mail you pointed to an example yourself [1]:
>>>
>>>
>>>  [1] pry(main)> "a".hash
>>>  => 100 [2] pry(main)> "\0a".hash
>>>  => 100 [3] pry(main)> "\0\0a".hash
>>>  => 100 [4] pry(main)> "\0\0\0a".hash
>>>  => 100 [5] pry(main)> "\0\0\0\0a".hash
>>>  => 100 [6] pry(main)>
>> "\0\0\0\0\0a".hash
>>>  => 100
>>>
>>
>> but you cannot put a \0 in a file name, because it is an invalid character
>> for a file name, right? We are looking for REAL file names that can result in
>> a viewId. For example:
>>
>> /home.xhtml
>> /module/page.xhtml
>>
>> and so on. In practice, the probability of have two REAL pages that derives a
>> viewId and that the hashCode could be the same is astronomical.
>>
>>>  It's just not guaranteed.
>>>
>>>  LieGrue,
>>>  strub
>>>
>>>
>>>
>>>  [1]
>> http://martin.kleppmann.com/2012/06/18/java-hashcode-unsafe-for-distributed-systems.html
>>>
>>>
>>>
>>>  ----- Original Message -----
>>>>  From: Leonardo Uribe <lu...@gmail.com>
>>>>  To: MyFaces Development <de...@myfaces.apache.org>; Mark Struberg
>> <st...@yahoo.de>
>>>>  Cc:
>>>>  Sent: Wednesday, November 14, 2012 11:34 PM
>>>>  Subject: Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./
>> src/main/java/org/apache/myfaces/renderkit/
>>>>
>>>>  2012/11/14 Leonardo Uribe <lu...@gmail.com>:
>>>>>   Hi
>>>>>
>>>>>   2012/11/14 Mark Struberg <st...@yahoo.de>:
>>>>>>   Leo, there was a reason I removed it.
>>>>>>
>>>>>>
>>>>>>   Even after discussing this over 10 mails in a private thread
>> you
>>>>  don't get it it seems. I will open a VOTE about principal design
>>>>  fundamentals and we will act according to this.
>>>>>>
>>>>>>   Just you be prepated: A HASH IS NOT UNIQUE!
>>>>>>
>>>>>
>>>>>   But I have told you multiple times, the algorithm does not rely on
>> the
>>>>>   hash to be unique, relies on the counter.
>>>>>
>>>>>>   Also saying in the mails you understand and then doing the
>> same crazy
>>>>  code again is just plain ******
>>>>>>
>>>>>>   I gonna revert it now and will write up the VOTE
>>>>>
>>>>>   The best way to resolve this is putting the arguments on the table
>> and
>>>>>   vote over that, right? after the vote we can do the necessary
>> changes
>>>>>   over the code. I have committed the fix that I suppose is correct.
>>>>>
>>>>
>>>>  It is more, could you please try if the fix proposed by me works in
>> your case?
>>>>  could you please show two viewIds that can be written as valid file
>> names that
>>>>  has the same hashCode? I'm open to change my mind, but first I need
>>>>  concrete arguments to do that.
>>>>
>>>>>   regards,
>>>>>
>>>>>   Leonardo
>>>>>
>>>>>>
>>>>>>   LieGrue,
>>>>>>   strub
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>   ----- Original Message -----
>>>>>>>   From: "lu4242@apache.org"
>> <lu...@apache.org>
>>>>>>>   To: commits@myfaces.apache.org
>>>>>>>   Cc:
>>>>>>>   Sent: Wednesday, November 14, 2012 10:23 PM
>>>>>>>   Subject: svn commit: r1409414 - in
>> /myfaces/core/trunk/impl: ./
>>>>  src/main/java/org/apache/myfaces/renderkit/
>>>>>>>
>>>>>>>   Author: lu4242
>>>>>>>   Date: Wed Nov 14 21:23:35 2012
>>>>>>>   New Revision: 1409414
>>>>>>>
>>>>>>>   URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
>>>>>>>   Log:
>>>>>>>   MYFACES-3638 revert commit 1408993 to include later
>> solution
>>>>  without
>>>>>>>   refactoring.
>>>>>>>
>>>>>>>   Added:
>>>>>>>
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>>>>         - copied unchanged from r1408992,
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>>>>   Removed:
>>>>>>>
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
>>>>>>>
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
>>>>>>>
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
>>>>>>>
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
>>>>>>>
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
>>>>>>>
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
>>>>>>>   Modified:
>>>>>>>       myfaces/core/trunk/impl/   (props changed)
>>>>>>>
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>>
>>>>>>>   Propchange: myfaces/core/trunk/impl/
>>>>>>>
>>>>
>> ------------------------------------------------------------------------------
>>>>>>>   --- svn:ignore (original)
>>>>>>>   +++ svn:ignore Wed Nov 14 21:23:35 2012
>>>>>>>   @@ -7,7 +7,8 @@ target
>>>>>>>   *.iml
>>>>>>>   *.ipr
>>>>>>>   *.iws
>>>>>>>   -.idea
>>>>>>>   .settings
>>>>>>>   +
>>>>>>>   cobertura.ser
>>>>>>>   +
>>>>>>>   test-output
>>>>>>>
>>>>>>>   Modified:
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>>   URL:
>>>>>>>
>>>>
>> http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
>>>>>>>
>>>>
>> ==============================================================================
>>>>>>>   ---
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>>   (original)
>>>>>>>   +++
>>>>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>>   Wed Nov 14 21:23:35 2012
>>>>>>>   @@ -30,16 +30,21 @@ import java.security.AccessController;
>>>>>>>   import java.security.PrivilegedActionException;
>>>>>>>   import java.security.PrivilegedExceptionAction;
>>>>>>>   import java.util.ArrayList;
>>>>>>>   +import java.util.Arrays;
>>>>>>>   import java.util.HashMap;
>>>>>>>   import java.util.List;
>>>>>>>   import java.util.Map;
>>>>>>>   +import java.util.Random;
>>>>>>>   import java.util.logging.Level;
>>>>>>>   import java.util.logging.Logger;
>>>>>>>   import java.util.zip.GZIPInputStream;
>>>>>>>   import java.util.zip.GZIPOutputStream;
>>>>>>>   +import javax.faces.application.ProjectStage;
>>>>>>>
>>>>>>>   import javax.faces.context.ExternalContext;
>>>>>>>   import javax.faces.context.FacesContext;
>>>>>>>   +import org.apache.commons.codec.DecoderException;
>>>>>>>   +import org.apache.commons.codec.binary.Hex;
>>>>>>>
>>>>>>>   import
>> org.apache.commons.collections.map.AbstractReferenceMap;
>>>>>>>   import org.apache.commons.collections.map.ReferenceMap;
>>>>>>>   @@ -52,22 +57,22 @@ import
>> org.apache.myfaces.shared.util.We
>>>>>>>   class ServerSideStateCacheImpl extends
>> StateCache<Object,
>>>>  Object>
>>>>>>>   {
>>>>>>>        private static final Logger log =
>>>>>>>
>> Logger.getLogger(ServerSideStateCacheImpl.class.getName());
>>>>>>>   -
>>>>>>>   -    private static final String
>> SERIALIZED_VIEW_SESSION_ATTR=
>>>>>>>   +
>>>>>>>   +    private static final String
>> SERIALIZED_VIEW_SESSION_ATTR=
>>>>>>>            ServerSideStateCacheImpl.class.getName() +
>>>>>>>   ".SERIALIZED_VIEW";
>>>>>>>   -
>>>>>>>   -    private static final String
>>>>  RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>>>>>   +
>>>>>>>   +    private static final String
>>>>  RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>>>>>            ServerSideStateCacheImpl.class.getName() +
>>>>>>>   ".RESTORED_SERIALIZED_VIEW";
>>>>>>>
>>>>>>>   -    private static final String
>> RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>>>>   +    private static final String
>> RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>>>>            ServerSideStateCacheImpl.class.getName() +
>>>>>>>   ".RESTORED_VIEW_KEY";
>>>>>>>   -
>>>>>>>   +
>>>>>>>        /**
>>>>>>>         * Defines the amount (default = 20) of the latest
>> views are
>>>>  stored in
>>>>>>>   session.
>>>>>>>   -     *
>>>>>>>   +     *
>>>>>>>         * <p>Only applicable if state saving method is
>>>>  "server" (=
>>>>>>>   default).
>>>>>>>         * </p>
>>>>>>>   -     *
>>>>>>>   +     *
>>>>>>>         */
>>>>>>>
>>>>  @JSFWebConfigParam(defaultValue="20",since="1.1",
>>>>>>>   classType="java.lang.Integer",
>> group="state",
>>>>>>>   tags="performance")
>>>>>>>        private static final String
>> NUMBER_OF_VIEWS_IN_SESSION_PARAM =
>>>>>>>   "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
>>>>>>>   @@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
>>>>>>>        /**
>>>>>>>         * 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>Only applicable if state saving method is
>>>>  "server" (=
>>>>>>>   default). For example, if this param has value = 2 and
>>>>>>>   +     *
>>>>>>>   +     * <p>Only applicable if state saving method is
>>>>  "server" (=
>>>>>>>   default). 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
>>>>>>>   @@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>        @JSFWebConfigParam(since="2.0.6",
>>>>>>>   classType="java.lang.Integer",
>> group="state",
>>>>>>>   tags="performance")
>>>>>>>        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;
>>>>>>>
>>>>>>>        /**
>>>>>>>   -     * Indicate if the state should be serialized before
>> save it
>>>>  on the
>>>>>>>   session.
>>>>>>>   +     * Indicate if the state should be serialized before
>> save it
>>>>  on the
>>>>>>>   session.
>>>>>>>         * <p>
>>>>>>>         * 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.
>>>>>>>   @@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>
>>>>>>>        /**
>>>>>>>         * Indicates that the serialized state will be
>> compressed
>>>>  before it is
>>>>>>>   written to the session. By default true.
>>>>>>>   -     *
>>>>>>>   +     *
>>>>>>>         * 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.
>>>>>>>   @@ -140,38 +145,38 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>         * <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>
>>>>>>>   +     * <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",
>>>>  group="state",
>>>>>>>   tags="performance")
>>>>>>>        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
>>>>>>>   +     * 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";
>>>>>>>
>>>>>>>        /**
>>>>>>>         * 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.
>>>>>>>   -     *
>>>>>>>   +     *
>>>>>>>         * <p>
>>>>>>>         * Only applicable if state saving method is
>>>>  "server" (=
>>>>>>>   default).
>>>>>>>         * The default value is false.</p>
>>>>>>>   @@ -183,84 +188,90 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>        private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE =
>>>>>>>   "none";
>>>>>>>        private static final String
>>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM =
>>>>  "secureRandom";
>>>>>>>        private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM =
>>>>>>>   "random";
>>>>>>>   -
>>>>>>>   +
>>>>>>>        /**
>>>>>>>         * Adds a random key to the generated view state
>> session
>>>>  token.
>>>>>>>         */
>>>>>>>   -    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>   expectedValues="secureRandom, random, none",
>>>>>>>   +    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>   expectedValues="secureRandom, random, none",
>>>>>>>                defaultValue="none",
>>>>  group="state")
>>>>>>>        private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
>>>>>>>                =
>>>>>>>
>>>>  "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
>>>>>>>   -    private static final String
>>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>>>>   +    private static final String
>>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>>>>                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
>>>>>>>
>>>>>>>        /**
>>>>>>>         * Set the default length of the random key added to
>> the view
>>>>  state session
>>>>>>>   token.
>>>>>>>   -     * By default is 8.
>>>>>>>   +     * By default is 8.
>>>>>>>         */
>>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>   defaultValue="8", group="state")
>>>>>>>   -    static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>>>>   +    private static final String
>>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>>>>                =
>>>>>>>
>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
>>>>>>>   -    static final int
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>>>>   +    private static final int
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>>>>
>>>>>>>        /**
>>>>>>>   -     * Sets the random class to initialize the secure
>> random id
>>>>  generator.
>>>>>>>   +     * Sets the random class to initialize the secure
>> random id
>>>>  generator.
>>>>>>>         * By default it uses java.security.SecureRandom
>>>>>>>         */
>>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>   group="state")
>>>>>>>   -    static final String
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>>>>   +    private static final String
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>>>>                =
>>>>>>>
>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
>>>>>>>   -
>>>>>>>   +
>>>>>>>        /**
>>>>>>>         * Sets the random provider to initialize the secure
>> random id
>>>>  generator.
>>>>>>>         */
>>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>   group="state")
>>>>>>>   -    static final String
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>>>>   +    private static final String
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>>>>                =
>>>>>>>
>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
>>>>>>>   -
>>>>>>>   +
>>>>>>>        /**
>>>>>>>   -     * Sets the random algorithm to initialize the secure
>> random
>>>>  id generator.
>>>>>>>   +     * Sets the random algorithm to initialize the secure
>> random
>>>>  id generator.
>>>>>>>         * By default is SHA1PRNG
>>>>>>>         */
>>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>>   defaultValue="SHA1PRNG",
>> group="state")
>>>>>>>   -    static final String
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>>>>   +    private static final String
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>>>>                =
>>>>>>>
>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
>>>>>>>   -
>>>>>>>   -
>>>>>>>   +
>>>>>>>   +
>>>>>>>        private static final int UNCOMPRESSED_FLAG = 0;
>>>>>>>        private static final int COMPRESSED_FLAG = 1;
>>>>>>>   -
>>>>>>>   +
>>>>>>>        private static final Object[] EMPTY_STATES = new
>>>>  Object[]{null, null};
>>>>>>>
>>>>>>>   +    //private static final int JSF_SEQUENCE_INDEX = 0;
>>>>>>>   +
>>>>>>>        private Boolean _useFlashScopePurgeViewsInSession =
>> null;
>>>>>>>   -
>>>>>>>   +
>>>>>>>        private Integer _numberOfSequentialViewsInSession =
>> null;
>>>>>>>        private boolean _numberOfSequentialViewsInSessionSet
>> = false;
>>>>>>>
>>>>>>>   +    //private final KeyFactory keyFactory;
>>>>>>>        private SessionViewStorageFactory
>> sessionViewStorageFactory;
>>>>>>>
>>>>>>>        public ServerSideStateCacheImpl()
>>>>>>>        {
>>>>>>>            FacesContext facesContext =
>>>>  FacesContext.getCurrentInstance();
>>>>>>>            String randomMode =
>>>>>>>
>>>>
>> WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
>>>>>>>   -
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>>>>   +
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>>>>
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
>>>>>>>            if
>>>>>>>
>>>>
>> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
>>>>>>>            {
>>>>>>>   -            sessionViewStorageFactory = new
>>>>  SessionViewStorageFactory(
>>>>>>>   +            //keyFactory = new
>>>>  SecureRandomKeyFactory(facesContext);
>>>>>>>   +            sessionViewStorageFactory = new
>>>>  RandomSessionViewStorageFactory(
>>>>>>>                        new
>> SecureRandomKeyFactory(facesContext));
>>>>>>>            }
>>>>>>>            else if
>>>>>>>
>> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
>>>>>>>            {
>>>>>>>   -            sessionViewStorageFactory = new
>>>>  SessionViewStorageFactory(
>>>>>>>   +            //keyFactory = new
>> RandomKeyFactory(facesContext);
>>>>>>>   +            sessionViewStorageFactory = new
>>>>  RandomSessionViewStorageFactory(
>>>>>>>                        new RandomKeyFactory(facesContext));
>>>>>>>            }
>>>>>>>            else
>>>>>>>            {
>>>>>>>   -            sessionViewStorageFactory = new
>>>>  SessionViewStorageFactory(new
>>>>>>>   CounterKeyFactory());
>>>>>>>   +            //keyFactory = new CounterKeyFactory();
>>>>>>>   +            sessionViewStorageFactory = new
>>>>>>>   CounterSessionViewStorageFactory(new CounterKeyFactory());
>>>>>>>            }
>>>>>>>        }
>>>>>>>   -
>>>>>>>   +
>>>>>>>        //------------------------------------- METHODS
>> COPIED FROM
>>>>>>>   JspStateManagerImpl--------------------------------
>>>>>>>
>>>>>>>        protected Object getServerStateId(FacesContext
>> facesContext,
>>>>  Object state)
>>>>>>>   @@ -285,16 +296,16 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>            }
>>>>>>>
>>>>>>>            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())
>>>>  &&
>>>>>>>   +                if
>>>>>>>
>> (isUseFlashScopePurgeViewsInSession(context.getExternalContext())
>>>>  &&
>>>>>>>
>>>>>>>
>> Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
>>>>>>>
>>>>>>>   .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
>>>>>>>                    {
>>>>>>>   @@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                    }
>>>>>>>                }
>>>>>>>            }
>>>>>>>   -
>>>>>>>   +
>>>>>>>            SerializedViewKey nextKey =
>>>>>>>   getSessionViewStorageFactory().createSerializedViewKey(
>>>>>>>                    context,
>> context.getViewRoot().getViewId(),
>>>>>>>   getNextViewSequence(context));
>>>>>>>            viewCollection.add(context,
>> serializeView(context,
>>>>  serializedView),
>>>>>>>   nextKey, key);
>>>>>>>   @@ -339,14 +350,14 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>                    }
>>>>>>>                }
>>>>>>>
>>>>  attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR,
>>>>>>>   serializedView);
>>>>>>>   -
>>>>>>>   +
>>>>>>>                if
>>>>  (getNumberOfSequentialViewsInSession(externalContext) != null
>>>>>>>   &&
>>>>>>>
>>>>  getNumberOfSequentialViewsInSession(externalContext) > 0)
>>>>>>>                {
>>>>>>>                    SerializedViewKey key =
>>>>  getSessionViewStorageFactory().
>>>>>>>                            createSerializedViewKey(context,
>> viewId,
>>>>  sequence);
>>>>>>>
>> attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR,
>>>>  key);
>>>>>>>   -
>>>>>>>   +
>>>>>>>                    if
>>>>  (isUseFlashScopePurgeViewsInSession(externalContext))
>>>>>>>                    {
>>>>>>>
>>>>>>>
>> externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR,
>>>>  key);
>>>>>>>   @@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                    //Object[] stateArray = (Object[])
>> serializedView;
>>>>>>>
>>>>>>>                    ObjectOutputStream out = new
>>>>  ObjectOutputStream(os);
>>>>>>>   -
>>>>>>>   +
>>>>>>>                    out.writeObject(serializedView);
>>>>>>>                    //out.writeObject(stateArray[0]);
>>>>>>>                    //out.writeObject(stateArray[1]);
>>>>>>>   @@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                        final ObjectInputStream in = new
>>>>>>>   MyFacesObjectInputStream(is);
>>>>>>>                        ois = in;
>>>>>>>                        Object object = null;
>>>>>>>   -                    if (System.getSecurityManager() !=
>> null)
>>>>>>>   +                    if (System.getSecurityManager() !=
>> null)
>>>>>>>                        {
>>>>>>>   -                        object =
>> AccessController.doPrivileged(new
>>>>>>>   PrivilegedExceptionAction<Object>()
>>>>>>>   +                        object =
>> AccessController.doPrivileged(new
>>>>>>>   PrivilegedExceptionAction<Object>()
>>>>>>>                            {
>>>>>>>                                public Object run() throws
>>>>>>>   PrivilegedActionException, IOException,
>> ClassNotFoundException
>>>>>>>                                {
>>>>>>>   @@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                        }
>>>>>>>                    }
>>>>>>>                }
>>>>>>>   -            catch (PrivilegedActionException e)
>>>>>>>   +            catch (PrivilegedActionException e)
>>>>>>>                {
>>>>>>>                    log.log(Level.SEVERE, "Exiting
>>>>  deserializeView - Could not
>>>>>>>   deserialize state: " + e.getMessage(), e);
>>>>>>>                    return null;
>>>>>>>   @@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                return null;
>>>>>>>            }
>>>>>>>        }
>>>>>>>   -
>>>>>>>   +
>>>>>>>        protected static class SerializedViewCollection
>> implements
>>>>  Serializable
>>>>>>>        {
>>>>>>>            private static final long serialVersionUID =
>>>>  -3734849062185115847L;
>>>>>>>   @@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>            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 =
>>>>>>>   +
>>>>>>>   +        private final Map<SerializedViewKey,
>>>>  SerializedViewKey>
>>>>>>>   _precedence =
>>>>>>>                new HashMap<SerializedViewKey,
>>>>  SerializedViewKey>();
>>>>>>>
>>>>>>>            // old views will be hold as soft references
>> which will be
>>>>  removed by
>>>>>>>   @@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                    // into the map.
>>>>>>>                    state = null;
>>>>>>>                }
>>>>>>>   -
>>>>>>>   +
>>>>>>>                Integer maxCount =
>>>>  getNumberOfSequentialViewsInSession(context);
>>>>>>>                if (maxCount != null)
>>>>>>>                {
>>>>>>>   @@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                      previousKey =
>> _precedence.get(previousKey);
>>>>>>>                      count++;
>>>>>>>                    } while (previousKey != null &&
>> count <
>>>>  maxCount);
>>>>>>>   -
>>>>>>>   +
>>>>>>>                    if (previousKey != null)
>>>>>>>                    {
>>>>>>>                        SerializedViewKey keyToRemove =
>>>>  (SerializedViewKey)
>>>>>>>   previousKey;
>>>>>>>   @@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                            {
>>>>>>>
>> _serializedViews.remove(keyToRemove);
>>>>>>>                            }
>>>>>>>   -
>>>>>>>   +
>>>>>>>                            keyToRemove =
>>>>  _precedence.remove(keyToRemove);
>>>>>>>                        }  while(keyToRemove != null);
>>>>>>>                    }
>>>>>>>   @@ -680,11 +691,11 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>                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,
>>>>>>>   +                    // 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
>>>>>>>   @@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                    if (_serializedViews.containsKey(key)
>> &&
>>>>>>>
>>>>>>>
>>>>
>> !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
>>>>>>>                    {
>>>>>>>   -
>>>>>>>   +
>>>>>>>                        getOldSerializedViewsMap().put(key,
>>>>>>>   _serializedViews.remove(key));
>>>>>>>                    }
>>>>>>>                    else
>>>>>>>   @@ -708,10 +719,10 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>
>>>>>>>            protected Integer
>>>>  getNumberOfSequentialViewsInSession(FacesContext
>>>>>>>   context)
>>>>>>>            {
>>>>>>>   -            return
>>>>>>>
>>>>
>> WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
>>>>>>>   +            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
>>>>>>>   @@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                FacesContext context =
>>>>  FacesContext.getCurrentInstance();
>>>>>>>                if (_oldSerializedViews == null &&
>> context !=
>>>>  null)
>>>>>>>                {
>>>>>>>   -                String cacheMode =
>>>>  getCacheOldViewsInSessionMode(context);
>>>>>>>   +                String cacheMode =
>>>>  getCacheOldViewsInSessionMode(context);
>>>>>>>                    if
>>>>  (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
>>>>>>>                    {
>>>>>>>                        _oldSerializedViews = new
>>>>>>>   ReferenceMap(AbstractReferenceMap.WEAK,
>> AbstractReferenceMap.WEAK,
>>>>  true);
>>>>>>>   @@ -773,13 +784,13 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>                        _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
>>>>>>>   @@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                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;
>>>>>>>   @@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends
>> S
>>>>>>>                    return
>> CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
>>>>>>>                }
>>>>>>>            }
>>>>>>>   -
>>>>>>>   +
>>>>>>>            public Object get(SerializedViewKey key)
>>>>>>>            {
>>>>>>>                Object value = _serializedViews.get(key);
>>>>>>>   @@ -846,7 +857,172 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>            }
>>>>>>>        }
>>>>>>>
>>>>>>>   +    /**
>>>>>>>   +     * Base implementation where all keys used to
>> identify the
>>>>  state of a view
>>>>>>>   should
>>>>>>>   +     * extend.
>>>>>>>   +     */
>>>>>>>   +    protected abstract static class SerializedViewKey
>> implements
>>>>  Serializable
>>>>>>>   +    {
>>>>>>>   +    }
>>>>>>>   +
>>>>>>>   +    /**
>>>>>>>   +     * Implementation of SerializedViewKey, where the
>> hashCode of
>>>>  the viewId is
>>>>>>>   used
>>>>>>>   +     * and the sequenceId is a numeric value.
>>>>>>>   +     */
>>>>>>>   +    private static class IntIntSerializedViewKey extends
>>>>  SerializedViewKey
>>>>>>>   +        implements Serializable
>>>>>>>   +    {
>>>>>>>   +        private static final long serialVersionUID =
>>>>  -1170697124386063642L;
>>>>>>>   +
>>>>>>>   +        private final int _viewId;
>>>>>>>   +        private final int _sequenceId;
>>>>>>>   +
>>>>>>>   +        public IntIntSerializedViewKey(int viewId, int
>> sequence)
>>>>>>>   +        {
>>>>>>>   +            _sequenceId = sequence;
>>>>>>>   +            _viewId = viewId;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public boolean equals(Object obj)
>>>>>>>   +        {
>>>>>>>   +            if (obj == null)
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            if (getClass() != obj.getClass())
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            final IntIntSerializedViewKey other =
>>>>  (IntIntSerializedViewKey)
>>>>>>>   obj;
>>>>>>>   +            if (this._viewId != other._viewId)
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            if (this._sequenceId != other._sequenceId)
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            return true;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public int hashCode()
>>>>>>>   +        {
>>>>>>>   +            int hash = 7;
>>>>>>>   +            hash = 83 * hash + this._viewId;
>>>>>>>   +            hash = 83 * hash + this._sequenceId;
>>>>>>>   +            return hash;
>>>>>>>   +        }
>>>>>>>   +    }
>>>>>>>   +
>>>>>>>   +    /**
>>>>>>>   +     * Implementation of SerializedViewKey, where the
>> hashCode of
>>>>  the viewId is
>>>>>>>   used
>>>>>>>   +     * and the sequenceId is a string value.
>>>>>>>   +     */
>>>>>>>   +    private static class IntByteArraySerializedViewKey
>> extends
>>>>>>>   SerializedViewKey
>>>>>>>   +        implements Serializable
>>>>>>>   +    {
>>>>>>>   +        private final int _viewId;
>>>>>>>   +        private final byte[] _sequenceId;
>>>>>>>   +
>>>>>>>   +        public IntByteArraySerializedViewKey(int viewId,
>> byte[]
>>>>  sequence)
>>>>>>>   +        {
>>>>>>>   +            _sequenceId = sequence;
>>>>>>>   +            _viewId = viewId;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public boolean equals(Object obj)
>>>>>>>   +        {
>>>>>>>   +            if (obj == null)
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            if (getClass() != obj.getClass())
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            final IntByteArraySerializedViewKey other =
>>>>>>>   (IntByteArraySerializedViewKey) obj;
>>>>>>>   +            if (this._viewId != other._viewId)
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            if (!Arrays.equals(this._sequenceId,
>>>>  other._sequenceId))
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            return true;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public int hashCode()
>>>>>>>   +        {
>>>>>>>   +            int hash = 5;
>>>>>>>   +            hash = 37 * hash + this._viewId;
>>>>>>>   +            hash = 37 * hash +
>> Arrays.hashCode(this._sequenceId);
>>>>>>>   +            return hash;
>>>>>>>   +        }
>>>>>>>   +    }
>>>>>>>   +
>>>>>>>   +
>>>>>>>   +    /**
>>>>>>>   +     * Implementation of SerializedViewKey, where the
>> viewId and
>>>>  the sequenceId
>>>>>>>   can be
>>>>>>>   +     * anything.
>>>>>>>   +     */
>>>>>>>   +    private static class
>> ReferenceSerializedViewKey<I,K>
>>>>  extends
>>>>>>>   SerializedViewKey
>>>>>>>   +        implements Serializable
>>>>>>>   +    {
>>>>>>>   +        private static final long serialVersionUID =
>>>>  -1170697124386063642L;
>>>>>>>   +
>>>>>>>   +        private final I _viewId;
>>>>>>>   +        private final K _sequenceId;
>>>>>>>
>>>>>>>   +        public ReferenceSerializedViewKey()
>>>>>>>   +        {
>>>>>>>   +            _sequenceId = null;
>>>>>>>   +            _viewId = null;
>>>>>>>   +        }
>>>>>>>   +        public ReferenceSerializedViewKey(I viewId, K
>> sequence)
>>>>>>>   +        {
>>>>>>>   +            _sequenceId = sequence;
>>>>>>>   +            _viewId = viewId;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public boolean equals(Object obj)
>>>>>>>   +        {
>>>>>>>   +            if (obj == null)
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            if (getClass() != obj.getClass())
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            final ReferenceSerializedViewKey<I, K>
>> other =
>>>>>>>   (ReferenceSerializedViewKey<I, K>) obj;
>>>>>>>   +            if (this._viewId != other._viewId &&
>>>>  (this._viewId == null
>>>>>>>   || !this._viewId.equals(other._viewId)))
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            if (this._sequenceId != other._sequenceId
>> &&
>>>>>>>   +                (this._sequenceId == null ||
>>>>>>>   !this._sequenceId.equals(other._sequenceId)))
>>>>>>>   +            {
>>>>>>>   +                return false;
>>>>>>>   +            }
>>>>>>>   +            return true;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public int hashCode()
>>>>>>>   +        {
>>>>>>>   +            int hash = 7;
>>>>>>>   +            hash = 83 * hash + (this._viewId != null ?
>>>>  this._viewId.hashCode()
>>>>>>>   : 0);
>>>>>>>   +            hash = 83 * hash + (this._sequenceId != null
>> ?
>>>>>>>   this._sequenceId.hashCode() : 0);
>>>>>>>   +            return hash;
>>>>>>>   +        }
>>>>>>>   +    }
>>>>>>>   +
>>>>>>>        //------------------------------------- METHOD FROM
>> StateCache
>>>>>>>   ------------------------------------------------
>>>>>>>
>>>>>>>        @Override
>>>>>>>   @@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>            }
>>>>>>>            //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);
>>>>>>>        }
>>>>>>>
>>>>>>>   @@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>        {
>>>>>>>            return
>>>>>>>
>>>>  getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
>>>>>>>        }
>>>>>>>   -
>>>>>>>   +
>>>>>>>        @Override
>>>>>>>        public boolean
>>>>  isWriteStateAfterRenderViewRequired(FacesContext
>>>>>>>   facesContext)
>>>>>>>        {
>>>>>>>   @@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>        }
>>>>>>>
>>>>>>>        //------------------------------------- Custom
>> methods
>>>>>>>   -----------------------------------------------------
>>>>>>>   -
>>>>>>>   +
>>>>>>>        private boolean
>>>>  isUseFlashScopePurgeViewsInSession(ExternalContext
>>>>>>>   externalContext)
>>>>>>>        {
>>>>>>>            if (_useFlashScopePurgeViewsInSession == null)
>>>>>>>   @@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl
>> extends S
>>>>>>>            }
>>>>>>>            return _useFlashScopePurgeViewsInSession;
>>>>>>>        }
>>>>>>>   -
>>>>>>>   +
>>>>>>>        private Integer
>>>>  getNumberOfSequentialViewsInSession(ExternalContext
>>>>>>>   externalContext)
>>>>>>>        {
>>>>>>>            if (!_numberOfSequentialViewsInSessionSet)
>>>>>>>            {
>>>>>>>                _numberOfSequentialViewsInSession =
>>>>>>>   WebConfigParamUtils.getIntegerInitParameter(
>>>>>>>   -                    externalContext,
>>>>>>>   +                    externalContext,
>>>>>>>
>> NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
>>>>>>>                _numberOfSequentialViewsInSessionSet = true;
>>>>>>>            }
>>>>>>>            return _numberOfSequentialViewsInSession;
>>>>>>>        }
>>>>>>>   -
>>>>>>>   +
>>>>>>>        protected KeyFactory getKeyFactory(FacesContext
>> facesContext)
>>>>>>>        {
>>>>>>>            //return keyFactory;
>>>>>>>            return sessionViewStorageFactory.getKeyFactory();
>>>>>>>        }
>>>>>>>   -
>>>>>>>   +
>>>>>>>        protected SessionViewStorageFactory
>>>>  getSessionViewStorageFactory()
>>>>>>>        {
>>>>>>>            return sessionViewStorageFactory;
>>>>>>>        }
>>>>>>>   +
>>>>>>>
>>>>>>>   +    protected abstract static class KeyFactory<K,
>> V>
>>>>>>>   +    {
>>>>>>>   +
>>>>>>>   +        /**
>>>>>>>   +         * Generates a unique key per session
>>>>>>>   +         *
>>>>>>>   +         * @param facesContext
>>>>>>>   +         * @return
>>>>>>>   +         */
>>>>>>>   +        public abstract K generateKey(FacesContext
>> facesContext);
>>>>>>>   +
>>>>>>>   +        /**
>>>>>>>   +         * Encode a Key into a value that will be used as
>> view
>>>>  state session
>>>>>>>   token
>>>>>>>   +         *
>>>>>>>   +         * @param key
>>>>>>>   +         * @return
>>>>>>>   +         */
>>>>>>>   +        public abstract V encode(K key);
>>>>>>>
>>>>>>>   +        /**
>>>>>>>   +         * Decode a view state session token into a key
>>>>>>>   +         *
>>>>>>>   +         * @param value
>>>>>>>   +         * @return
>>>>>>>   +         */
>>>>>>>   +        public abstract K decode(V value);
>>>>>>>   +
>>>>>>>   +    }
>>>>>>>   +
>>>>>>>   +    private static class CounterKeyFactory extends
>>>>  KeyFactory<Integer,
>>>>>>>   String>
>>>>>>>   +    {
>>>>>>>   +        /**
>>>>>>>   +         * Take the counter from session scope and
>> increment
>>>>>>>   +         *
>>>>>>>   +         * @param facesContext
>>>>>>>   +         * @return
>>>>>>>   +         */
>>>>>>>   +        @Override
>>>>>>>   +        public Integer generateKey(FacesContext
>> facesContext)
>>>>>>>   +        {
>>>>>>>   +            ExternalContext externalContext =
>>>>>>>   facesContext.getExternalContext();
>>>>>>>   +            Object sessionObj =
>> externalContext.getSession(true);
>>>>>>>   +            Integer sequence = null;
>>>>>>>   +            synchronized(sessionObj) // synchronized to
>> increase
>>>>  sequence if
>>>>>>>   multiple requests
>>>>>>>   +                                    // are handled at the
>> same
>>>>  time for the
>>>>>>>   session
>>>>>>>   +            {
>>>>>>>   +                Map<String, Object> map =
>>>>>>>   externalContext.getSessionMap();
>>>>>>>   +                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);
>>>>>>>   +            }
>>>>>>>   +            return sequence;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        public String encode(Integer sequence)
>>>>>>>   +        {
>>>>>>>   +            return Integer.toString(sequence,
>>>>  Character.MAX_RADIX);
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        public Integer decode(String serverStateId)
>>>>>>>   +        {
>>>>>>>   +             return Integer.valueOf((String)
>> serverStateId,
>>>>>>>   Character.MAX_RADIX);
>>>>>>>   +        }
>>>>>>>   +    }
>>>>>>>   +
>>>>>>>   +    /**
>>>>>>>   +     * This factory generate a key composed by a counter
>> and a
>>>>  random number.
>>>>>>>   The
>>>>>>>   +     * counter ensures uniqueness, and the random number
>> prevents
>>>>  guess the
>>>>>>>   next
>>>>>>>   +     * session token.
>>>>>>>   +     */
>>>>>>>   +    private static class SecureRandomKeyFactory extends
>>>>  KeyFactory<byte[],
>>>>>>>   String>
>>>>>>>   +    {
>>>>>>>   +        private final SessionIdGenerator
>> sessionIdGenerator;
>>>>>>>   +        private final int length;
>>>>>>>   +
>>>>>>>   +        public SecureRandomKeyFactory(FacesContext
>> facesContext)
>>>>>>>   +        {
>>>>>>>   +            length =
>>>>>>>
>>>>
>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>>>>   +
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>>>>   +
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>>>>   +            sessionIdGenerator = new
>> SessionIdGenerator();
>>>>>>>   +
>> sessionIdGenerator.setSessionIdLength(length);
>>>>>>>   +            String secureRandomClass =
>>>>>>>   WebConfigParamUtils.getStringInitParameter(
>>>>>>>   +                    facesContext.getExternalContext(),
>>>>>>>   +
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
>>>>>>>   +            if (secureRandomClass != null)
>>>>>>>   +            {
>>>>>>>   +
>>>>  sessionIdGenerator.setSecureRandomClass(secureRandomClass);
>>>>>>>   +            }
>>>>>>>   +            String secureRandomProvider =
>>>>>>>   WebConfigParamUtils.getStringInitParameter(
>>>>>>>   +                    facesContext.getExternalContext(),
>>>>>>>   +
>>>>>>>
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
>>>>>>>   +            if (secureRandomProvider != null)
>>>>>>>   +            {
>>>>>>>   +
>>>>>>>
>> sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
>>>>>>>   +            }
>>>>>>>   +            String secureRandomAlgorithm =
>>>>>>>   WebConfigParamUtils.getStringInitParameter(
>>>>>>>   +                    facesContext.getExternalContext(),
>>>>>>>   +
>>>>>>>
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
>>>>>>>   +            if (secureRandomAlgorithm != null)
>>>>>>>   +            {
>>>>>>>   +
>>>>>>>
>> sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
>>>>>>>   +            }
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        public Integer generateCounterKey(FacesContext
>>>>  facesContext)
>>>>>>>   +        {
>>>>>>>   +            ExternalContext externalContext =
>>>>>>>   facesContext.getExternalContext();
>>>>>>>   +            Object sessionObj =
>> externalContext.getSession(true);
>>>>>>>   +            Integer sequence = null;
>>>>>>>   +            synchronized(sessionObj) // synchronized to
>> increase
>>>>  sequence if
>>>>>>>   multiple requests
>>>>>>>   +                                    // are handled at the
>> same
>>>>  time for the
>>>>>>>   session
>>>>>>>   +            {
>>>>>>>   +                Map<String, Object> map =
>>>>>>>   externalContext.getSessionMap();
>>>>>>>   +                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);
>>>>>>>   +            }
>>>>>>>   +            return sequence;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public byte[] generateKey(FacesContext
>> facesContext)
>>>>>>>   +        {
>>>>>>>   +            byte[] array = new byte[length];
>>>>>>>   +            byte[] key = new byte[length+4];
>>>>>>>   +
>>>>>>>   +            sessionIdGenerator.getRandomBytes(array);
>>>>>>>   +            for (int i = 0; i < array.length; i++)
>>>>>>>   +            {
>>>>>>>   +                key[i] = array[i];
>>>>>>>   +            }
>>>>>>>   +            int value = generateCounterKey(facesContext);
>>>>>>>   +            key[array.length] =  (byte) (value
>>>>>  24);
>>>>>>>   +            key[array.length+1] =  (byte) (value
>>>>>  16);
>>>>>>>   +            key[array.length+2] =  (byte) (value
>>>>>  8);
>>>>>>>   +            key[array.length+3] =  (byte) (value);
>>>>>>>   +
>>>>>>>   +            return key;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public String encode(byte[] key)
>>>>>>>   +        {
>>>>>>>   +            return new String(Hex.encodeHex(key));
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public byte[] decode(String value)
>>>>>>>   +        {
>>>>>>>   +            try
>>>>>>>   +            {
>>>>>>>   +                return
>> Hex.decodeHex(value.toCharArray());
>>>>>>>   +            }
>>>>>>>   +            catch (DecoderException ex)
>>>>>>>   +            {
>>>>>>>   +                // Cannot decode, ignore silently, later
>> it will
>>>>  be handled as
>>>>>>>   +                // ViewExpiredException
>>>>>>>   +            }
>>>>>>>   +            return null;
>>>>>>>   +        }
>>>>>>>   +    }
>>>>>>>   +
>>>>>>>   +    private static class RandomKeyFactory extends
>>>>  KeyFactory<byte[],
>>>>>>>   String>
>>>>>>>   +    {
>>>>>>>   +        private final Random random;
>>>>>>>   +        private final int length;
>>>>>>>   +
>>>>>>>   +        public RandomKeyFactory(FacesContext
>> facesContext)
>>>>>>>   +        {
>>>>>>>   +            length =
>>>>>>>
>>>>
>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>>>>   +
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>>>>   +
>>>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>>>>   +            random = new
>>>>  Random(((int)System.nanoTime())+this.hashCode());
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        public Integer generateCounterKey(FacesContext
>>>>  facesContext)
>>>>>>>   +        {
>>>>>>>   +            ExternalContext externalContext =
>>>>>>>   facesContext.getExternalContext();
>>>>>>>   +            Object sessionObj =
>> externalContext.getSession(true);
>>>>>>>   +            Integer sequence = null;
>>>>>>>   +            synchronized(sessionObj) // synchronized to
>> increase
>>>>  sequence if
>>>>>>>   multiple requests
>>>>>>>   +                                    // are handled at the
>> same
>>>>  time for the
>>>>>>>   session
>>>>>>>   +            {
>>>>>>>   +                Map<String, Object> map =
>>>>>>>   externalContext.getSessionMap();
>>>>>>>   +                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);
>>>>>>>   +            }
>>>>>>>   +            return sequence;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public byte[] generateKey(FacesContext
>> facesContext)
>>>>>>>   +        {
>>>>>>>   +            byte[] array = new byte[length];
>>>>>>>   +            byte[] key = new byte[length+4];
>>>>>>>   +
>>>>>>>   +            //sessionIdGenerator.getRandomBytes(array);
>>>>>>>   +            random.nextBytes(array);
>>>>>>>   +            for (int i = 0; i < array.length; i++)
>>>>>>>   +            {
>>>>>>>   +                key[i] = array[i];
>>>>>>>   +            }
>>>>>>>   +            int value = generateCounterKey(facesContext);
>>>>>>>   +            key[array.length] =  (byte) (value
>>>>>  24);
>>>>>>>   +            key[array.length+1] =  (byte) (value
>>>>>  16);
>>>>>>>   +            key[array.length+2] =  (byte) (value
>>>>>  8);
>>>>>>>   +            key[array.length+3] =  (byte) (value);
>>>>>>>   +
>>>>>>>   +            return key;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public String encode(byte[] key)
>>>>>>>   +        {
>>>>>>>   +            return new String(Hex.encodeHex(key));
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public byte[] decode(String value)
>>>>>>>   +        {
>>>>>>>   +            try
>>>>>>>   +            {
>>>>>>>   +                return
>> Hex.decodeHex(value.toCharArray());
>>>>>>>   +            }
>>>>>>>   +            catch (DecoderException ex)
>>>>>>>   +            {
>>>>>>>   +                // Cannot decode, ignore silently, later
>> it will
>>>>  be handled as
>>>>>>>   +                // ViewExpiredException
>>>>>>>   +            }
>>>>>>>   +            return null;
>>>>>>>   +        }
>>>>>>>   +    }
>>>>>>>   +
>>>>>>>   +    /**
>>>>>>>   +     *
>>>>>>>   +     * @param <T>
>>>>>>>   +     * @param <K>
>>>>>>>   +     * @param <V>
>>>>>>>   +     */
>>>>>>>   +    protected abstract static class
>> SessionViewStorageFactory
>>>>  <T extends
>>>>>>>   KeyFactory<K,V>, K, V >
>>>>>>>   +    {
>>>>>>>   +        private KeyFactory<K, V> keyFactory;
>>>>>>>   +
>>>>>>>   +        public SessionViewStorageFactory(KeyFactory<K,
>> V>
>>>>  keyFactory)
>>>>>>>   +        {
>>>>>>>   +            this.keyFactory = keyFactory;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        public KeyFactory<K, V> getKeyFactory()
>>>>>>>   +        {
>>>>>>>   +            return keyFactory;
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        public abstract SerializedViewCollection
>>>>>>>   createSerializedViewCollection(
>>>>>>>   +                FacesContext context);
>>>>>>>   +
>>>>>>>   +        public abstract SerializedViewKey
>> createSerializedViewKey(
>>>>>>>   +                FacesContext facesContext, String viewId,
>> K key);
>>>>>>>   +
>>>>>>>   +    }
>>>>>>>   +
>>>>>>>   +    private static class CounterSessionViewStorageFactory
>>>>>>>   +        extends SessionViewStorageFactory <KeyFactory
>>>>>>>   <Integer,String>, Integer, String>
>>>>>>>   +    {
>>>>>>>   +        public
>>>>  CounterSessionViewStorageFactory(KeyFactory<Integer,
>>>>>>>   String> keyFactory)
>>>>>>>   +        {
>>>>>>>   +            super(keyFactory);
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public SerializedViewCollection
>>>>  createSerializedViewCollection(
>>>>>>>   +                FacesContext context)
>>>>>>>   +        {
>>>>>>>   +            return new SerializedViewCollection();
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public SerializedViewKey createSerializedViewKey(
>>>>>>>   +                FacesContext context, String viewId,
>> Integer key)
>>>>>>>   +        {
>>>>>>>   +            if
>> (context.isProjectStage(ProjectStage.Production))
>>>>>>>   +            {
>>>>>>>   +                return new
>>>>  IntIntSerializedViewKey(viewId.hashCode(), key);
>>>>>>>   +            }
>>>>>>>   +            else
>>>>>>>   +            {
>>>>>>>   +                return new
>> ReferenceSerializedViewKey(viewId,
>>>>  key);
>>>>>>>   +            }
>>>>>>>   +        }
>>>>>>>   +    }
>>>>>>>   +
>>>>>>>   +    private static class RandomSessionViewStorageFactory
>>>>>>>   +        extends SessionViewStorageFactory <KeyFactory
>>>>  <byte[],String>,
>>>>>>>   byte[], String>
>>>>>>>   +    {
>>>>>>>   +        public
>>>>  RandomSessionViewStorageFactory(KeyFactory<byte[], String>
>>>>>>>   keyFactory)
>>>>>>>   +        {
>>>>>>>   +            super(keyFactory);
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public SerializedViewCollection
>>>>  createSerializedViewCollection(
>>>>>>>   +                FacesContext context)
>>>>>>>   +        {
>>>>>>>   +            return new SerializedViewCollection();
>>>>>>>   +        }
>>>>>>>   +
>>>>>>>   +        @Override
>>>>>>>   +        public SerializedViewKey createSerializedViewKey(
>>>>>>>   +                FacesContext context, String viewId,
>> byte[] key)
>>>>>>>   +        {
>>>>>>>   +            if
>> (context.isProjectStage(ProjectStage.Production))
>>>>>>>   +            {
>>>>>>>   +                return new
>>>>  IntByteArraySerializedViewKey(viewId.hashCode(),
>>>>>>>   key);
>>>>>>>   +            }
>>>>>>>   +            else
>>>>>>>   +            {
>>>>>>>   +                return new
>> ReferenceSerializedViewKey(viewId,
>>>>  key);
>>>>>>>   +            }
>>>>>>>   +        }
>>>>>>>   +    }
>>>>>>>   }
>>>>>>>
>>>>
>>

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Mark Struberg <st...@yahoo.de>.
> hat the hashCode could be the same is astronomical.

I thought so the same, but Udo did hit that in production. This really happens!
And I really don't care about storing 20 bytes more because the encryption which is done immediately afterwards will use much more memory.


Again: if the viewId would not needed for uniqueness, then we could also drop it completely.


LieGrue,
strub



----- Original Message -----
> From: Leonardo Uribe <lu...@gmail.com>
> To: MyFaces Development <de...@myfaces.apache.org>; Mark Struberg <st...@yahoo.de>
> Cc: 
> Sent: Wednesday, November 14, 2012 11:50 PM
> Subject: Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/
> 
> 2012/11/14 Mark Struberg <st...@yahoo.de>:
>> 
>> 
>> 
>> 
>>  Leo we HAD that already in production (with an IBM JVM). Does that count?
>> 
>>  using the hashCode to speed up caches is perfectly fine. But only for 
> _excluding_ matches, Getting the same hashCode doesn't make sure something 
> is unique.
>> 
>>  Also in the private mail you pointed to an example yourself [1]:
>> 
>> 
>>  [1] pry(main)> "a".hash
>>  => 100 [2] pry(main)> "\0a".hash
>>  => 100 [3] pry(main)> "\0\0a".hash
>>  => 100 [4] pry(main)> "\0\0\0a".hash
>>  => 100 [5] pry(main)> "\0\0\0\0a".hash
>>  => 100 [6] pry(main)> 
> "\0\0\0\0\0a".hash
>>  => 100
>> 
> 
> but you cannot put a \0 in a file name, because it is an invalid character
> for a file name, right? We are looking for REAL file names that can result in
> a viewId. For example:
> 
> /home.xhtml
> /module/page.xhtml
> 
> and so on. In practice, the probability of have two REAL pages that derives a
> viewId and that the hashCode could be the same is astronomical.
> 
>>  It's just not guaranteed.
>> 
>>  LieGrue,
>>  strub
>> 
>> 
>> 
>>  [1] 
> http://martin.kleppmann.com/2012/06/18/java-hashcode-unsafe-for-distributed-systems.html
>> 
>> 
>> 
>>  ----- Original Message -----
>>>  From: Leonardo Uribe <lu...@gmail.com>
>>>  To: MyFaces Development <de...@myfaces.apache.org>; Mark Struberg 
> <st...@yahoo.de>
>>>  Cc:
>>>  Sent: Wednesday, November 14, 2012 11:34 PM
>>>  Subject: Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ 
> src/main/java/org/apache/myfaces/renderkit/
>>> 
>>>  2012/11/14 Leonardo Uribe <lu...@gmail.com>:
>>>>   Hi
>>>> 
>>>>   2012/11/14 Mark Struberg <st...@yahoo.de>:
>>>>>   Leo, there was a reason I removed it.
>>>>> 
>>>>> 
>>>>>   Even after discussing this over 10 mails in a private thread 
> you
>>>  don't get it it seems. I will open a VOTE about principal design
>>>  fundamentals and we will act according to this.
>>>>> 
>>>>>   Just you be prepated: A HASH IS NOT UNIQUE!
>>>>> 
>>>> 
>>>>   But I have told you multiple times, the algorithm does not rely on 
> the
>>>>   hash to be unique, relies on the counter.
>>>> 
>>>>>   Also saying in the mails you understand and then doing the 
> same crazy
>>>  code again is just plain ******
>>>>> 
>>>>>   I gonna revert it now and will write up the VOTE
>>>> 
>>>>   The best way to resolve this is putting the arguments on the table 
> and
>>>>   vote over that, right? after the vote we can do the necessary 
> changes
>>>>   over the code. I have committed the fix that I suppose is correct.
>>>> 
>>> 
>>>  It is more, could you please try if the fix proposed by me works in 
> your case?
>>>  could you please show two viewIds that can be written as valid file 
> names that
>>>  has the same hashCode? I'm open to change my mind, but first I need
>>>  concrete arguments to do that.
>>> 
>>>>   regards,
>>>> 
>>>>   Leonardo
>>>> 
>>>>> 
>>>>>   LieGrue,
>>>>>   strub
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>>   ----- Original Message -----
>>>>>>   From: "lu4242@apache.org" 
> <lu...@apache.org>
>>>>>>   To: commits@myfaces.apache.org
>>>>>>   Cc:
>>>>>>   Sent: Wednesday, November 14, 2012 10:23 PM
>>>>>>   Subject: svn commit: r1409414 - in 
> /myfaces/core/trunk/impl: ./
>>>  src/main/java/org/apache/myfaces/renderkit/
>>>>>> 
>>>>>>   Author: lu4242
>>>>>>   Date: Wed Nov 14 21:23:35 2012
>>>>>>   New Revision: 1409414
>>>>>> 
>>>>>>   URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
>>>>>>   Log:
>>>>>>   MYFACES-3638 revert commit 1408993 to include later 
> solution
>>>  without
>>>>>>   refactoring.
>>>>>> 
>>>>>>   Added:
>>>>>> 
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>>>         - copied unchanged from r1408992,
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>>>   Removed:
>>>>>> 
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
>>>>>> 
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
>>>>>> 
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
>>>>>> 
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
>>>>>> 
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
>>>>>> 
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
>>>>>>   Modified:
>>>>>>       myfaces/core/trunk/impl/   (props changed)
>>>>>> 
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>> 
>>>>>>   Propchange: myfaces/core/trunk/impl/
>>>>>> 
>>> 
> ------------------------------------------------------------------------------
>>>>>>   --- svn:ignore (original)
>>>>>>   +++ svn:ignore Wed Nov 14 21:23:35 2012
>>>>>>   @@ -7,7 +7,8 @@ target
>>>>>>   *.iml
>>>>>>   *.ipr
>>>>>>   *.iws
>>>>>>   -.idea
>>>>>>   .settings
>>>>>>   +
>>>>>>   cobertura.ser
>>>>>>   +
>>>>>>   test-output
>>>>>> 
>>>>>>   Modified:
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>   URL:
>>>>>> 
>>> 
> http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
>>>>>> 
>>> 
> ==============================================================================
>>>>>>   ---
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>   (original)
>>>>>>   +++
>>>>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>>   Wed Nov 14 21:23:35 2012
>>>>>>   @@ -30,16 +30,21 @@ import java.security.AccessController;
>>>>>>   import java.security.PrivilegedActionException;
>>>>>>   import java.security.PrivilegedExceptionAction;
>>>>>>   import java.util.ArrayList;
>>>>>>   +import java.util.Arrays;
>>>>>>   import java.util.HashMap;
>>>>>>   import java.util.List;
>>>>>>   import java.util.Map;
>>>>>>   +import java.util.Random;
>>>>>>   import java.util.logging.Level;
>>>>>>   import java.util.logging.Logger;
>>>>>>   import java.util.zip.GZIPInputStream;
>>>>>>   import java.util.zip.GZIPOutputStream;
>>>>>>   +import javax.faces.application.ProjectStage;
>>>>>> 
>>>>>>   import javax.faces.context.ExternalContext;
>>>>>>   import javax.faces.context.FacesContext;
>>>>>>   +import org.apache.commons.codec.DecoderException;
>>>>>>   +import org.apache.commons.codec.binary.Hex;
>>>>>> 
>>>>>>   import 
> org.apache.commons.collections.map.AbstractReferenceMap;
>>>>>>   import org.apache.commons.collections.map.ReferenceMap;
>>>>>>   @@ -52,22 +57,22 @@ import 
> org.apache.myfaces.shared.util.We
>>>>>>   class ServerSideStateCacheImpl extends 
> StateCache<Object,
>>>  Object>
>>>>>>   {
>>>>>>        private static final Logger log =
>>>>>>   
> Logger.getLogger(ServerSideStateCacheImpl.class.getName());
>>>>>>   -
>>>>>>   -    private static final String 
> SERIALIZED_VIEW_SESSION_ATTR=
>>>>>>   +
>>>>>>   +    private static final String 
> SERIALIZED_VIEW_SESSION_ATTR=
>>>>>>            ServerSideStateCacheImpl.class.getName() +
>>>>>>   ".SERIALIZED_VIEW";
>>>>>>   -
>>>>>>   -    private static final String
>>>  RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>>>>   +
>>>>>>   +    private static final String
>>>  RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>>>>            ServerSideStateCacheImpl.class.getName() +
>>>>>>   ".RESTORED_SERIALIZED_VIEW";
>>>>>> 
>>>>>>   -    private static final String 
> RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>>>   +    private static final String 
> RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>>>            ServerSideStateCacheImpl.class.getName() +
>>>>>>   ".RESTORED_VIEW_KEY";
>>>>>>   -
>>>>>>   +
>>>>>>        /**
>>>>>>         * Defines the amount (default = 20) of the latest 
> views are
>>>  stored in
>>>>>>   session.
>>>>>>   -     *
>>>>>>   +     *
>>>>>>         * <p>Only applicable if state saving method is
>>>  "server" (=
>>>>>>   default).
>>>>>>         * </p>
>>>>>>   -     *
>>>>>>   +     *
>>>>>>         */
>>>>>> 
>>>  @JSFWebConfigParam(defaultValue="20",since="1.1",
>>>>>>   classType="java.lang.Integer", 
> group="state",
>>>>>>   tags="performance")
>>>>>>        private static final String 
> NUMBER_OF_VIEWS_IN_SESSION_PARAM =
>>>>>>   "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
>>>>>>   @@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
>>>>>>        /**
>>>>>>         * 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>Only applicable if state saving method is
>>>  "server" (=
>>>>>>   default). For example, if this param has value = 2 and
>>>>>>   +     *
>>>>>>   +     * <p>Only applicable if state saving method is
>>>  "server" (=
>>>>>>   default). 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
>>>>>>   @@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>        @JSFWebConfigParam(since="2.0.6",
>>>>>>   classType="java.lang.Integer", 
> group="state",
>>>>>>   tags="performance")
>>>>>>        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;
>>>>>> 
>>>>>>        /**
>>>>>>   -     * Indicate if the state should be serialized before 
> save it
>>>  on the
>>>>>>   session.
>>>>>>   +     * Indicate if the state should be serialized before 
> save it
>>>  on the
>>>>>>   session.
>>>>>>         * <p>
>>>>>>         * 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.
>>>>>>   @@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>> 
>>>>>>        /**
>>>>>>         * Indicates that the serialized state will be 
> compressed
>>>  before it is
>>>>>>   written to the session. By default true.
>>>>>>   -     *
>>>>>>   +     *
>>>>>>         * 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.
>>>>>>   @@ -140,38 +145,38 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>         * <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>
>>>>>>   +     * <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",
>>>  group="state",
>>>>>>   tags="performance")
>>>>>>        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
>>>>>>   +     * 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";
>>>>>> 
>>>>>>        /**
>>>>>>         * 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.
>>>>>>   -     *
>>>>>>   +     *
>>>>>>         * <p>
>>>>>>         * Only applicable if state saving method is
>>>  "server" (=
>>>>>>   default).
>>>>>>         * The default value is false.</p>
>>>>>>   @@ -183,84 +188,90 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>        private static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE =
>>>>>>   "none";
>>>>>>        private static final String
>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM =
>>>  "secureRandom";
>>>>>>        private static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM =
>>>>>>   "random";
>>>>>>   -
>>>>>>   +
>>>>>>        /**
>>>>>>         * Adds a random key to the generated view state 
> session
>>>  token.
>>>>>>         */
>>>>>>   -    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>   expectedValues="secureRandom, random, none",
>>>>>>   +    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>   expectedValues="secureRandom, random, none",
>>>>>>                defaultValue="none",
>>>  group="state")
>>>>>>        private static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
>>>>>>                =
>>>>>> 
>>>  "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
>>>>>>   -    private static final String
>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>>>   +    private static final String
>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>>>                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
>>>>>> 
>>>>>>        /**
>>>>>>         * Set the default length of the random key added to 
> the view
>>>  state session
>>>>>>   token.
>>>>>>   -     * By default is 8.
>>>>>>   +     * By default is 8.
>>>>>>         */
>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>   defaultValue="8", group="state")
>>>>>>   -    static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>>>   +    private static final String
>>>>>>   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>>>                =
>>>>>> 
>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
>>>>>>   -    static final int
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>>>   +    private static final int
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>>> 
>>>>>>        /**
>>>>>>   -     * Sets the random class to initialize the secure 
> random id
>>>  generator.
>>>>>>   +     * Sets the random class to initialize the secure 
> random id
>>>  generator.
>>>>>>         * By default it uses java.security.SecureRandom
>>>>>>         */
>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>   group="state")
>>>>>>   -    static final String
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>>>   +    private static final String
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>>>                =
>>>>>> 
>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
>>>>>>   -
>>>>>>   +
>>>>>>        /**
>>>>>>         * Sets the random provider to initialize the secure 
> random id
>>>  generator.
>>>>>>         */
>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>   group="state")
>>>>>>   -    static final String
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>>>   +    private static final String
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>>>                =
>>>>>> 
>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
>>>>>>   -
>>>>>>   +
>>>>>>        /**
>>>>>>   -     * Sets the random algorithm to initialize the secure 
> random
>>>  id generator.
>>>>>>   +     * Sets the random algorithm to initialize the secure 
> random
>>>  id generator.
>>>>>>         * By default is SHA1PRNG
>>>>>>         */
>>>>>>        @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>>   defaultValue="SHA1PRNG", 
> group="state")
>>>>>>   -    static final String
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>>>   +    private static final String
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>>>                =
>>>>>> 
>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
>>>>>>   -
>>>>>>   -
>>>>>>   +
>>>>>>   +
>>>>>>        private static final int UNCOMPRESSED_FLAG = 0;
>>>>>>        private static final int COMPRESSED_FLAG = 1;
>>>>>>   -
>>>>>>   +
>>>>>>        private static final Object[] EMPTY_STATES = new
>>>  Object[]{null, null};
>>>>>> 
>>>>>>   +    //private static final int JSF_SEQUENCE_INDEX = 0;
>>>>>>   +
>>>>>>        private Boolean _useFlashScopePurgeViewsInSession = 
> null;
>>>>>>   -
>>>>>>   +
>>>>>>        private Integer _numberOfSequentialViewsInSession = 
> null;
>>>>>>        private boolean _numberOfSequentialViewsInSessionSet 
> = false;
>>>>>> 
>>>>>>   +    //private final KeyFactory keyFactory;
>>>>>>        private SessionViewStorageFactory 
> sessionViewStorageFactory;
>>>>>> 
>>>>>>        public ServerSideStateCacheImpl()
>>>>>>        {
>>>>>>            FacesContext facesContext =
>>>  FacesContext.getCurrentInstance();
>>>>>>            String randomMode =
>>>>>> 
>>> 
> WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
>>>>>>   -                
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>>>   +                
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>>> 
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
>>>>>>            if
>>>>>> 
>>> 
> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
>>>>>>            {
>>>>>>   -            sessionViewStorageFactory = new
>>>  SessionViewStorageFactory(
>>>>>>   +            //keyFactory = new
>>>  SecureRandomKeyFactory(facesContext);
>>>>>>   +            sessionViewStorageFactory = new
>>>  RandomSessionViewStorageFactory(
>>>>>>                        new 
> SecureRandomKeyFactory(facesContext));
>>>>>>            }
>>>>>>            else if
>>>>>>   
> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
>>>>>>            {
>>>>>>   -            sessionViewStorageFactory = new
>>>  SessionViewStorageFactory(
>>>>>>   +            //keyFactory = new 
> RandomKeyFactory(facesContext);
>>>>>>   +            sessionViewStorageFactory = new
>>>  RandomSessionViewStorageFactory(
>>>>>>                        new RandomKeyFactory(facesContext));
>>>>>>            }
>>>>>>            else
>>>>>>            {
>>>>>>   -            sessionViewStorageFactory = new
>>>  SessionViewStorageFactory(new
>>>>>>   CounterKeyFactory());
>>>>>>   +            //keyFactory = new CounterKeyFactory();
>>>>>>   +            sessionViewStorageFactory = new
>>>>>>   CounterSessionViewStorageFactory(new CounterKeyFactory());
>>>>>>            }
>>>>>>        }
>>>>>>   -
>>>>>>   +
>>>>>>        //------------------------------------- METHODS 
> COPIED FROM
>>>>>>   JspStateManagerImpl--------------------------------
>>>>>> 
>>>>>>        protected Object getServerStateId(FacesContext 
> facesContext,
>>>  Object state)
>>>>>>   @@ -285,16 +296,16 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>            }
>>>>>> 
>>>>>>            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())
>>>  &&
>>>>>>   +                if
>>>>>>   
> (isUseFlashScopePurgeViewsInSession(context.getExternalContext())
>>>  &&
>>>>>> 
>>>>>>   
> Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
>>>>>> 
>>>>>>   .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
>>>>>>                    {
>>>>>>   @@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                    }
>>>>>>                }
>>>>>>            }
>>>>>>   -
>>>>>>   +
>>>>>>            SerializedViewKey nextKey =
>>>>>>   getSessionViewStorageFactory().createSerializedViewKey(
>>>>>>                    context, 
> context.getViewRoot().getViewId(),
>>>>>>   getNextViewSequence(context));
>>>>>>            viewCollection.add(context, 
> serializeView(context,
>>>  serializedView),
>>>>>>   nextKey, key);
>>>>>>   @@ -339,14 +350,14 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>                    }
>>>>>>                }
>>>>>> 
>>>  attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR,
>>>>>>   serializedView);
>>>>>>   -
>>>>>>   +
>>>>>>                if
>>>  (getNumberOfSequentialViewsInSession(externalContext) != null
>>>>>>   &&
>>>>>> 
>>>  getNumberOfSequentialViewsInSession(externalContext) > 0)
>>>>>>                {
>>>>>>                    SerializedViewKey key =
>>>  getSessionViewStorageFactory().
>>>>>>                            createSerializedViewKey(context, 
> viewId,
>>>  sequence);
>>>>>>                   
> attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR,
>>>  key);
>>>>>>   -
>>>>>>   +
>>>>>>                    if
>>>  (isUseFlashScopePurgeViewsInSession(externalContext))
>>>>>>                    {
>>>>>> 
>>>>>>   
> externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR,
>>>  key);
>>>>>>   @@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                    //Object[] stateArray = (Object[]) 
> serializedView;
>>>>>> 
>>>>>>                    ObjectOutputStream out = new
>>>  ObjectOutputStream(os);
>>>>>>   -
>>>>>>   +
>>>>>>                    out.writeObject(serializedView);
>>>>>>                    //out.writeObject(stateArray[0]);
>>>>>>                    //out.writeObject(stateArray[1]);
>>>>>>   @@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                        final ObjectInputStream in = new
>>>>>>   MyFacesObjectInputStream(is);
>>>>>>                        ois = in;
>>>>>>                        Object object = null;
>>>>>>   -                    if (System.getSecurityManager() != 
> null)
>>>>>>   +                    if (System.getSecurityManager() != 
> null)
>>>>>>                        {
>>>>>>   -                        object = 
> AccessController.doPrivileged(new
>>>>>>   PrivilegedExceptionAction<Object>()
>>>>>>   +                        object = 
> AccessController.doPrivileged(new
>>>>>>   PrivilegedExceptionAction<Object>()
>>>>>>                            {
>>>>>>                                public Object run() throws
>>>>>>   PrivilegedActionException, IOException, 
> ClassNotFoundException
>>>>>>                                {
>>>>>>   @@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                        }
>>>>>>                    }
>>>>>>                }
>>>>>>   -            catch (PrivilegedActionException e)
>>>>>>   +            catch (PrivilegedActionException e)
>>>>>>                {
>>>>>>                    log.log(Level.SEVERE, "Exiting
>>>  deserializeView - Could not
>>>>>>   deserialize state: " + e.getMessage(), e);
>>>>>>                    return null;
>>>>>>   @@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                return null;
>>>>>>            }
>>>>>>        }
>>>>>>   -
>>>>>>   +
>>>>>>        protected static class SerializedViewCollection 
> implements
>>>  Serializable
>>>>>>        {
>>>>>>            private static final long serialVersionUID =
>>>  -3734849062185115847L;
>>>>>>   @@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>            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 =
>>>>>>   +
>>>>>>   +        private final Map<SerializedViewKey,
>>>  SerializedViewKey>
>>>>>>   _precedence =
>>>>>>                new HashMap<SerializedViewKey,
>>>  SerializedViewKey>();
>>>>>> 
>>>>>>            // old views will be hold as soft references 
> which will be
>>>  removed by
>>>>>>   @@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                    // into the map.
>>>>>>                    state = null;
>>>>>>                }
>>>>>>   -
>>>>>>   +
>>>>>>                Integer maxCount =
>>>  getNumberOfSequentialViewsInSession(context);
>>>>>>                if (maxCount != null)
>>>>>>                {
>>>>>>   @@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                      previousKey = 
> _precedence.get(previousKey);
>>>>>>                      count++;
>>>>>>                    } while (previousKey != null && 
> count <
>>>  maxCount);
>>>>>>   -
>>>>>>   +
>>>>>>                    if (previousKey != null)
>>>>>>                    {
>>>>>>                        SerializedViewKey keyToRemove =
>>>  (SerializedViewKey)
>>>>>>   previousKey;
>>>>>>   @@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                            {
>>>>>>                               
> _serializedViews.remove(keyToRemove);
>>>>>>                            }
>>>>>>   -
>>>>>>   +
>>>>>>                            keyToRemove =
>>>  _precedence.remove(keyToRemove);
>>>>>>                        }  while(keyToRemove != null);
>>>>>>                    }
>>>>>>   @@ -680,11 +691,11 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>                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,
>>>>>>   +                    // 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
>>>>>>   @@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                    if (_serializedViews.containsKey(key) 
> &&
>>>>>> 
>>>>>> 
>>> 
> !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
>>>>>>                    {
>>>>>>   -
>>>>>>   +
>>>>>>                        getOldSerializedViewsMap().put(key,
>>>>>>   _serializedViews.remove(key));
>>>>>>                    }
>>>>>>                    else
>>>>>>   @@ -708,10 +719,10 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>> 
>>>>>>            protected Integer
>>>  getNumberOfSequentialViewsInSession(FacesContext
>>>>>>   context)
>>>>>>            {
>>>>>>   -            return
>>>>>> 
>>> 
> WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
>>>>>>   +            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
>>>>>>   @@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                FacesContext context =
>>>  FacesContext.getCurrentInstance();
>>>>>>                if (_oldSerializedViews == null && 
> context !=
>>>  null)
>>>>>>                {
>>>>>>   -                String cacheMode =
>>>  getCacheOldViewsInSessionMode(context);
>>>>>>   +                String cacheMode =
>>>  getCacheOldViewsInSessionMode(context);
>>>>>>                    if
>>>  (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
>>>>>>                    {
>>>>>>                        _oldSerializedViews = new
>>>>>>   ReferenceMap(AbstractReferenceMap.WEAK, 
> AbstractReferenceMap.WEAK,
>>>  true);
>>>>>>   @@ -773,13 +784,13 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>                        _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
>>>>>>   @@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                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;
>>>>>>   @@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends 
> S
>>>>>>                    return 
> CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
>>>>>>                }
>>>>>>            }
>>>>>>   -
>>>>>>   +
>>>>>>            public Object get(SerializedViewKey key)
>>>>>>            {
>>>>>>                Object value = _serializedViews.get(key);
>>>>>>   @@ -846,7 +857,172 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>            }
>>>>>>        }
>>>>>> 
>>>>>>   +    /**
>>>>>>   +     * Base implementation where all keys used to 
> identify the
>>>  state of a view
>>>>>>   should
>>>>>>   +     * extend.
>>>>>>   +     */
>>>>>>   +    protected abstract static class SerializedViewKey 
> implements
>>>  Serializable
>>>>>>   +    {
>>>>>>   +    }
>>>>>>   +
>>>>>>   +    /**
>>>>>>   +     * Implementation of SerializedViewKey, where the 
> hashCode of
>>>  the viewId is
>>>>>>   used
>>>>>>   +     * and the sequenceId is a numeric value.
>>>>>>   +     */
>>>>>>   +    private static class IntIntSerializedViewKey extends
>>>  SerializedViewKey
>>>>>>   +        implements Serializable
>>>>>>   +    {
>>>>>>   +        private static final long serialVersionUID =
>>>  -1170697124386063642L;
>>>>>>   +
>>>>>>   +        private final int _viewId;
>>>>>>   +        private final int _sequenceId;
>>>>>>   +
>>>>>>   +        public IntIntSerializedViewKey(int viewId, int 
> sequence)
>>>>>>   +        {
>>>>>>   +            _sequenceId = sequence;
>>>>>>   +            _viewId = viewId;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public boolean equals(Object obj)
>>>>>>   +        {
>>>>>>   +            if (obj == null)
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            if (getClass() != obj.getClass())
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            final IntIntSerializedViewKey other =
>>>  (IntIntSerializedViewKey)
>>>>>>   obj;
>>>>>>   +            if (this._viewId != other._viewId)
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            if (this._sequenceId != other._sequenceId)
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            return true;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public int hashCode()
>>>>>>   +        {
>>>>>>   +            int hash = 7;
>>>>>>   +            hash = 83 * hash + this._viewId;
>>>>>>   +            hash = 83 * hash + this._sequenceId;
>>>>>>   +            return hash;
>>>>>>   +        }
>>>>>>   +    }
>>>>>>   +
>>>>>>   +    /**
>>>>>>   +     * Implementation of SerializedViewKey, where the 
> hashCode of
>>>  the viewId is
>>>>>>   used
>>>>>>   +     * and the sequenceId is a string value.
>>>>>>   +     */
>>>>>>   +    private static class IntByteArraySerializedViewKey 
> extends
>>>>>>   SerializedViewKey
>>>>>>   +        implements Serializable
>>>>>>   +    {
>>>>>>   +        private final int _viewId;
>>>>>>   +        private final byte[] _sequenceId;
>>>>>>   +
>>>>>>   +        public IntByteArraySerializedViewKey(int viewId, 
> byte[]
>>>  sequence)
>>>>>>   +        {
>>>>>>   +            _sequenceId = sequence;
>>>>>>   +            _viewId = viewId;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public boolean equals(Object obj)
>>>>>>   +        {
>>>>>>   +            if (obj == null)
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            if (getClass() != obj.getClass())
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            final IntByteArraySerializedViewKey other =
>>>>>>   (IntByteArraySerializedViewKey) obj;
>>>>>>   +            if (this._viewId != other._viewId)
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            if (!Arrays.equals(this._sequenceId,
>>>  other._sequenceId))
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            return true;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public int hashCode()
>>>>>>   +        {
>>>>>>   +            int hash = 5;
>>>>>>   +            hash = 37 * hash + this._viewId;
>>>>>>   +            hash = 37 * hash + 
> Arrays.hashCode(this._sequenceId);
>>>>>>   +            return hash;
>>>>>>   +        }
>>>>>>   +    }
>>>>>>   +
>>>>>>   +
>>>>>>   +    /**
>>>>>>   +     * Implementation of SerializedViewKey, where the 
> viewId and
>>>  the sequenceId
>>>>>>   can be
>>>>>>   +     * anything.
>>>>>>   +     */
>>>>>>   +    private static class 
> ReferenceSerializedViewKey<I,K>
>>>  extends
>>>>>>   SerializedViewKey
>>>>>>   +        implements Serializable
>>>>>>   +    {
>>>>>>   +        private static final long serialVersionUID =
>>>  -1170697124386063642L;
>>>>>>   +
>>>>>>   +        private final I _viewId;
>>>>>>   +        private final K _sequenceId;
>>>>>> 
>>>>>>   +        public ReferenceSerializedViewKey()
>>>>>>   +        {
>>>>>>   +            _sequenceId = null;
>>>>>>   +            _viewId = null;
>>>>>>   +        }
>>>>>>   +        public ReferenceSerializedViewKey(I viewId, K 
> sequence)
>>>>>>   +        {
>>>>>>   +            _sequenceId = sequence;
>>>>>>   +            _viewId = viewId;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public boolean equals(Object obj)
>>>>>>   +        {
>>>>>>   +            if (obj == null)
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            if (getClass() != obj.getClass())
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            final ReferenceSerializedViewKey<I, K> 
> other =
>>>>>>   (ReferenceSerializedViewKey<I, K>) obj;
>>>>>>   +            if (this._viewId != other._viewId &&
>>>  (this._viewId == null
>>>>>>   || !this._viewId.equals(other._viewId)))
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            if (this._sequenceId != other._sequenceId 
> &&
>>>>>>   +                (this._sequenceId == null ||
>>>>>>   !this._sequenceId.equals(other._sequenceId)))
>>>>>>   +            {
>>>>>>   +                return false;
>>>>>>   +            }
>>>>>>   +            return true;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public int hashCode()
>>>>>>   +        {
>>>>>>   +            int hash = 7;
>>>>>>   +            hash = 83 * hash + (this._viewId != null ?
>>>  this._viewId.hashCode()
>>>>>>   : 0);
>>>>>>   +            hash = 83 * hash + (this._sequenceId != null 
> ?
>>>>>>   this._sequenceId.hashCode() : 0);
>>>>>>   +            return hash;
>>>>>>   +        }
>>>>>>   +    }
>>>>>>   +
>>>>>>        //------------------------------------- METHOD FROM 
> StateCache
>>>>>>   ------------------------------------------------
>>>>>> 
>>>>>>        @Override
>>>>>>   @@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>            }
>>>>>>            //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);
>>>>>>        }
>>>>>> 
>>>>>>   @@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>        {
>>>>>>            return
>>>>>> 
>>>  getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
>>>>>>        }
>>>>>>   -
>>>>>>   +
>>>>>>        @Override
>>>>>>        public boolean
>>>  isWriteStateAfterRenderViewRequired(FacesContext
>>>>>>   facesContext)
>>>>>>        {
>>>>>>   @@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>        }
>>>>>> 
>>>>>>        //------------------------------------- Custom 
> methods
>>>>>>   -----------------------------------------------------
>>>>>>   -
>>>>>>   +
>>>>>>        private boolean
>>>  isUseFlashScopePurgeViewsInSession(ExternalContext
>>>>>>   externalContext)
>>>>>>        {
>>>>>>            if (_useFlashScopePurgeViewsInSession == null)
>>>>>>   @@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl 
> extends S
>>>>>>            }
>>>>>>            return _useFlashScopePurgeViewsInSession;
>>>>>>        }
>>>>>>   -
>>>>>>   +
>>>>>>        private Integer
>>>  getNumberOfSequentialViewsInSession(ExternalContext
>>>>>>   externalContext)
>>>>>>        {
>>>>>>            if (!_numberOfSequentialViewsInSessionSet)
>>>>>>            {
>>>>>>                _numberOfSequentialViewsInSession =
>>>>>>   WebConfigParamUtils.getIntegerInitParameter(
>>>>>>   -                    externalContext,
>>>>>>   +                    externalContext,
>>>>>>                       
> NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
>>>>>>                _numberOfSequentialViewsInSessionSet = true;
>>>>>>            }
>>>>>>            return _numberOfSequentialViewsInSession;
>>>>>>        }
>>>>>>   -
>>>>>>   +
>>>>>>        protected KeyFactory getKeyFactory(FacesContext 
> facesContext)
>>>>>>        {
>>>>>>            //return keyFactory;
>>>>>>            return sessionViewStorageFactory.getKeyFactory();
>>>>>>        }
>>>>>>   -
>>>>>>   +
>>>>>>        protected SessionViewStorageFactory
>>>  getSessionViewStorageFactory()
>>>>>>        {
>>>>>>            return sessionViewStorageFactory;
>>>>>>        }
>>>>>>   +
>>>>>> 
>>>>>>   +    protected abstract static class KeyFactory<K, 
> V>
>>>>>>   +    {
>>>>>>   +
>>>>>>   +        /**
>>>>>>   +         * Generates a unique key per session
>>>>>>   +         *
>>>>>>   +         * @param facesContext
>>>>>>   +         * @return
>>>>>>   +         */
>>>>>>   +        public abstract K generateKey(FacesContext 
> facesContext);
>>>>>>   +
>>>>>>   +        /**
>>>>>>   +         * Encode a Key into a value that will be used as 
> view
>>>  state session
>>>>>>   token
>>>>>>   +         *
>>>>>>   +         * @param key
>>>>>>   +         * @return
>>>>>>   +         */
>>>>>>   +        public abstract V encode(K key);
>>>>>> 
>>>>>>   +        /**
>>>>>>   +         * Decode a view state session token into a key
>>>>>>   +         *
>>>>>>   +         * @param value
>>>>>>   +         * @return
>>>>>>   +         */
>>>>>>   +        public abstract K decode(V value);
>>>>>>   +
>>>>>>   +    }
>>>>>>   +
>>>>>>   +    private static class CounterKeyFactory extends
>>>  KeyFactory<Integer,
>>>>>>   String>
>>>>>>   +    {
>>>>>>   +        /**
>>>>>>   +         * Take the counter from session scope and 
> increment
>>>>>>   +         *
>>>>>>   +         * @param facesContext
>>>>>>   +         * @return
>>>>>>   +         */
>>>>>>   +        @Override
>>>>>>   +        public Integer generateKey(FacesContext 
> facesContext)
>>>>>>   +        {
>>>>>>   +            ExternalContext externalContext =
>>>>>>   facesContext.getExternalContext();
>>>>>>   +            Object sessionObj = 
> externalContext.getSession(true);
>>>>>>   +            Integer sequence = null;
>>>>>>   +            synchronized(sessionObj) // synchronized to 
> increase
>>>  sequence if
>>>>>>   multiple requests
>>>>>>   +                                    // are handled at the 
> same
>>>  time for the
>>>>>>   session
>>>>>>   +            {
>>>>>>   +                Map<String, Object> map =
>>>>>>   externalContext.getSessionMap();
>>>>>>   +                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);
>>>>>>   +            }
>>>>>>   +            return sequence;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        public String encode(Integer sequence)
>>>>>>   +        {
>>>>>>   +            return Integer.toString(sequence,
>>>  Character.MAX_RADIX);
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        public Integer decode(String serverStateId)
>>>>>>   +        {
>>>>>>   +             return Integer.valueOf((String) 
> serverStateId,
>>>>>>   Character.MAX_RADIX);
>>>>>>   +        }
>>>>>>   +    }
>>>>>>   +
>>>>>>   +    /**
>>>>>>   +     * This factory generate a key composed by a counter 
> and a
>>>  random number.
>>>>>>   The
>>>>>>   +     * counter ensures uniqueness, and the random number 
> prevents
>>>  guess the
>>>>>>   next
>>>>>>   +     * session token.
>>>>>>   +     */
>>>>>>   +    private static class SecureRandomKeyFactory extends
>>>  KeyFactory<byte[],
>>>>>>   String>
>>>>>>   +    {
>>>>>>   +        private final SessionIdGenerator 
> sessionIdGenerator;
>>>>>>   +        private final int length;
>>>>>>   +
>>>>>>   +        public SecureRandomKeyFactory(FacesContext 
> facesContext)
>>>>>>   +        {
>>>>>>   +            length =
>>>>>> 
>>> 
> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>>>   +
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>>>   +
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>>>   +            sessionIdGenerator = new 
> SessionIdGenerator();
>>>>>>   +            
> sessionIdGenerator.setSessionIdLength(length);
>>>>>>   +            String secureRandomClass =
>>>>>>   WebConfigParamUtils.getStringInitParameter(
>>>>>>   +                    facesContext.getExternalContext(),
>>>>>>   +
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
>>>>>>   +            if (secureRandomClass != null)
>>>>>>   +            {
>>>>>>   +
>>>  sessionIdGenerator.setSecureRandomClass(secureRandomClass);
>>>>>>   +            }
>>>>>>   +            String secureRandomProvider =
>>>>>>   WebConfigParamUtils.getStringInitParameter(
>>>>>>   +                    facesContext.getExternalContext(),
>>>>>>   +
>>>>>> 
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
>>>>>>   +            if (secureRandomProvider != null)
>>>>>>   +            {
>>>>>>   +
>>>>>>   
> sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
>>>>>>   +            }
>>>>>>   +            String secureRandomAlgorithm =
>>>>>>   WebConfigParamUtils.getStringInitParameter(
>>>>>>   +                    facesContext.getExternalContext(),
>>>>>>   +
>>>>>> 
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
>>>>>>   +            if (secureRandomAlgorithm != null)
>>>>>>   +            {
>>>>>>   +
>>>>>>   
> sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
>>>>>>   +            }
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        public Integer generateCounterKey(FacesContext
>>>  facesContext)
>>>>>>   +        {
>>>>>>   +            ExternalContext externalContext =
>>>>>>   facesContext.getExternalContext();
>>>>>>   +            Object sessionObj = 
> externalContext.getSession(true);
>>>>>>   +            Integer sequence = null;
>>>>>>   +            synchronized(sessionObj) // synchronized to 
> increase
>>>  sequence if
>>>>>>   multiple requests
>>>>>>   +                                    // are handled at the 
> same
>>>  time for the
>>>>>>   session
>>>>>>   +            {
>>>>>>   +                Map<String, Object> map =
>>>>>>   externalContext.getSessionMap();
>>>>>>   +                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);
>>>>>>   +            }
>>>>>>   +            return sequence;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public byte[] generateKey(FacesContext 
> facesContext)
>>>>>>   +        {
>>>>>>   +            byte[] array = new byte[length];
>>>>>>   +            byte[] key = new byte[length+4];
>>>>>>   +
>>>>>>   +            sessionIdGenerator.getRandomBytes(array);
>>>>>>   +            for (int i = 0; i < array.length; i++)
>>>>>>   +            {
>>>>>>   +                key[i] = array[i];
>>>>>>   +            }
>>>>>>   +            int value = generateCounterKey(facesContext);
>>>>>>   +            key[array.length] =  (byte) (value 
>>>>  24);
>>>>>>   +            key[array.length+1] =  (byte) (value 
>>>>  16);
>>>>>>   +            key[array.length+2] =  (byte) (value 
>>>>  8);
>>>>>>   +            key[array.length+3] =  (byte) (value);
>>>>>>   +
>>>>>>   +            return key;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public String encode(byte[] key)
>>>>>>   +        {
>>>>>>   +            return new String(Hex.encodeHex(key));
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public byte[] decode(String value)
>>>>>>   +        {
>>>>>>   +            try
>>>>>>   +            {
>>>>>>   +                return 
> Hex.decodeHex(value.toCharArray());
>>>>>>   +            }
>>>>>>   +            catch (DecoderException ex)
>>>>>>   +            {
>>>>>>   +                // Cannot decode, ignore silently, later 
> it will
>>>  be handled as
>>>>>>   +                // ViewExpiredException
>>>>>>   +            }
>>>>>>   +            return null;
>>>>>>   +        }
>>>>>>   +    }
>>>>>>   +
>>>>>>   +    private static class RandomKeyFactory extends
>>>  KeyFactory<byte[],
>>>>>>   String>
>>>>>>   +    {
>>>>>>   +        private final Random random;
>>>>>>   +        private final int length;
>>>>>>   +
>>>>>>   +        public RandomKeyFactory(FacesContext 
> facesContext)
>>>>>>   +        {
>>>>>>   +            length =
>>>>>> 
>>> 
> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>>>   +
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>>>   +
>>>>>>   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>>>   +            random = new
>>>  Random(((int)System.nanoTime())+this.hashCode());
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        public Integer generateCounterKey(FacesContext
>>>  facesContext)
>>>>>>   +        {
>>>>>>   +            ExternalContext externalContext =
>>>>>>   facesContext.getExternalContext();
>>>>>>   +            Object sessionObj = 
> externalContext.getSession(true);
>>>>>>   +            Integer sequence = null;
>>>>>>   +            synchronized(sessionObj) // synchronized to 
> increase
>>>  sequence if
>>>>>>   multiple requests
>>>>>>   +                                    // are handled at the 
> same
>>>  time for the
>>>>>>   session
>>>>>>   +            {
>>>>>>   +                Map<String, Object> map =
>>>>>>   externalContext.getSessionMap();
>>>>>>   +                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);
>>>>>>   +            }
>>>>>>   +            return sequence;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public byte[] generateKey(FacesContext 
> facesContext)
>>>>>>   +        {
>>>>>>   +            byte[] array = new byte[length];
>>>>>>   +            byte[] key = new byte[length+4];
>>>>>>   +
>>>>>>   +            //sessionIdGenerator.getRandomBytes(array);
>>>>>>   +            random.nextBytes(array);
>>>>>>   +            for (int i = 0; i < array.length; i++)
>>>>>>   +            {
>>>>>>   +                key[i] = array[i];
>>>>>>   +            }
>>>>>>   +            int value = generateCounterKey(facesContext);
>>>>>>   +            key[array.length] =  (byte) (value 
>>>>  24);
>>>>>>   +            key[array.length+1] =  (byte) (value 
>>>>  16);
>>>>>>   +            key[array.length+2] =  (byte) (value 
>>>>  8);
>>>>>>   +            key[array.length+3] =  (byte) (value);
>>>>>>   +
>>>>>>   +            return key;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public String encode(byte[] key)
>>>>>>   +        {
>>>>>>   +            return new String(Hex.encodeHex(key));
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public byte[] decode(String value)
>>>>>>   +        {
>>>>>>   +            try
>>>>>>   +            {
>>>>>>   +                return 
> Hex.decodeHex(value.toCharArray());
>>>>>>   +            }
>>>>>>   +            catch (DecoderException ex)
>>>>>>   +            {
>>>>>>   +                // Cannot decode, ignore silently, later 
> it will
>>>  be handled as
>>>>>>   +                // ViewExpiredException
>>>>>>   +            }
>>>>>>   +            return null;
>>>>>>   +        }
>>>>>>   +    }
>>>>>>   +
>>>>>>   +    /**
>>>>>>   +     *
>>>>>>   +     * @param <T>
>>>>>>   +     * @param <K>
>>>>>>   +     * @param <V>
>>>>>>   +     */
>>>>>>   +    protected abstract static class 
> SessionViewStorageFactory
>>>  <T extends
>>>>>>   KeyFactory<K,V>, K, V >
>>>>>>   +    {
>>>>>>   +        private KeyFactory<K, V> keyFactory;
>>>>>>   +
>>>>>>   +        public SessionViewStorageFactory(KeyFactory<K, 
> V>
>>>  keyFactory)
>>>>>>   +        {
>>>>>>   +            this.keyFactory = keyFactory;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        public KeyFactory<K, V> getKeyFactory()
>>>>>>   +        {
>>>>>>   +            return keyFactory;
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        public abstract SerializedViewCollection
>>>>>>   createSerializedViewCollection(
>>>>>>   +                FacesContext context);
>>>>>>   +
>>>>>>   +        public abstract SerializedViewKey 
> createSerializedViewKey(
>>>>>>   +                FacesContext facesContext, String viewId, 
> K key);
>>>>>>   +
>>>>>>   +    }
>>>>>>   +
>>>>>>   +    private static class CounterSessionViewStorageFactory
>>>>>>   +        extends SessionViewStorageFactory <KeyFactory
>>>>>>   <Integer,String>, Integer, String>
>>>>>>   +    {
>>>>>>   +        public
>>>  CounterSessionViewStorageFactory(KeyFactory<Integer,
>>>>>>   String> keyFactory)
>>>>>>   +        {
>>>>>>   +            super(keyFactory);
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public SerializedViewCollection
>>>  createSerializedViewCollection(
>>>>>>   +                FacesContext context)
>>>>>>   +        {
>>>>>>   +            return new SerializedViewCollection();
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public SerializedViewKey createSerializedViewKey(
>>>>>>   +                FacesContext context, String viewId, 
> Integer key)
>>>>>>   +        {
>>>>>>   +            if 
> (context.isProjectStage(ProjectStage.Production))
>>>>>>   +            {
>>>>>>   +                return new
>>>  IntIntSerializedViewKey(viewId.hashCode(), key);
>>>>>>   +            }
>>>>>>   +            else
>>>>>>   +            {
>>>>>>   +                return new 
> ReferenceSerializedViewKey(viewId,
>>>  key);
>>>>>>   +            }
>>>>>>   +        }
>>>>>>   +    }
>>>>>>   +
>>>>>>   +    private static class RandomSessionViewStorageFactory
>>>>>>   +        extends SessionViewStorageFactory <KeyFactory
>>>  <byte[],String>,
>>>>>>   byte[], String>
>>>>>>   +    {
>>>>>>   +        public
>>>  RandomSessionViewStorageFactory(KeyFactory<byte[], String>
>>>>>>   keyFactory)
>>>>>>   +        {
>>>>>>   +            super(keyFactory);
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public SerializedViewCollection
>>>  createSerializedViewCollection(
>>>>>>   +                FacesContext context)
>>>>>>   +        {
>>>>>>   +            return new SerializedViewCollection();
>>>>>>   +        }
>>>>>>   +
>>>>>>   +        @Override
>>>>>>   +        public SerializedViewKey createSerializedViewKey(
>>>>>>   +                FacesContext context, String viewId, 
> byte[] key)
>>>>>>   +        {
>>>>>>   +            if 
> (context.isProjectStage(ProjectStage.Production))
>>>>>>   +            {
>>>>>>   +                return new
>>>  IntByteArraySerializedViewKey(viewId.hashCode(),
>>>>>>   key);
>>>>>>   +            }
>>>>>>   +            else
>>>>>>   +            {
>>>>>>   +                return new 
> ReferenceSerializedViewKey(viewId,
>>>  key);
>>>>>>   +            }
>>>>>>   +        }
>>>>>>   +    }
>>>>>>   }
>>>>>> 
>>> 
> 

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Leonardo Uribe <lu...@gmail.com>.
2012/11/14 Mark Struberg <st...@yahoo.de>:
>
>
>
>
> Leo we HAD that already in production (with an IBM JVM). Does that count?
>
> using the hashCode to speed up caches is perfectly fine. But only for _excluding_ matches, Getting the same hashCode doesn't make sure something is unique.
>
> Also in the private mail you pointed to an example yourself [1]:
>
>
> [1] pry(main)> "a".hash
> => 100 [2] pry(main)> "\0a".hash
> => 100 [3] pry(main)> "\0\0a".hash
> => 100 [4] pry(main)> "\0\0\0a".hash
> => 100 [5] pry(main)> "\0\0\0\0a".hash
> => 100 [6] pry(main)> "\0\0\0\0\0a".hash
> => 100
>

but you cannot put a \0 in a file name, because it is an invalid character
for a file name, right? We are looking for REAL file names that can result in
a viewId. For example:

 /home.xhtml
 /module/page.xhtml

and so on. In practice, the probability of have two REAL pages that derives a
viewId and that the hashCode could be the same is astronomical.

> It's just not guaranteed.
>
> LieGrue,
> strub
>
>
>
> [1] http://martin.kleppmann.com/2012/06/18/java-hashcode-unsafe-for-distributed-systems.html
>
>
>
> ----- Original Message -----
>> From: Leonardo Uribe <lu...@gmail.com>
>> To: MyFaces Development <de...@myfaces.apache.org>; Mark Struberg <st...@yahoo.de>
>> Cc:
>> Sent: Wednesday, November 14, 2012 11:34 PM
>> Subject: Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/
>>
>> 2012/11/14 Leonardo Uribe <lu...@gmail.com>:
>>>  Hi
>>>
>>>  2012/11/14 Mark Struberg <st...@yahoo.de>:
>>>>  Leo, there was a reason I removed it.
>>>>
>>>>
>>>>  Even after discussing this over 10 mails in a private thread you
>> don't get it it seems. I will open a VOTE about principal design
>> fundamentals and we will act according to this.
>>>>
>>>>  Just you be prepated: A HASH IS NOT UNIQUE!
>>>>
>>>
>>>  But I have told you multiple times, the algorithm does not rely on the
>>>  hash to be unique, relies on the counter.
>>>
>>>>  Also saying in the mails you understand and then doing the same crazy
>> code again is just plain ******
>>>>
>>>>  I gonna revert it now and will write up the VOTE
>>>
>>>  The best way to resolve this is putting the arguments on the table and
>>>  vote over that, right? after the vote we can do the necessary changes
>>>  over the code. I have committed the fix that I suppose is correct.
>>>
>>
>> It is more, could you please try if the fix proposed by me works in your case?
>> could you please show two viewIds that can be written as valid file names that
>> has the same hashCode? I'm open to change my mind, but first I need
>> concrete arguments to do that.
>>
>>>  regards,
>>>
>>>  Leonardo
>>>
>>>>
>>>>  LieGrue,
>>>>  strub
>>>>
>>>>
>>>>
>>>>
>>>>  ----- Original Message -----
>>>>>  From: "lu4242@apache.org" <lu...@apache.org>
>>>>>  To: commits@myfaces.apache.org
>>>>>  Cc:
>>>>>  Sent: Wednesday, November 14, 2012 10:23 PM
>>>>>  Subject: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./
>> src/main/java/org/apache/myfaces/renderkit/
>>>>>
>>>>>  Author: lu4242
>>>>>  Date: Wed Nov 14 21:23:35 2012
>>>>>  New Revision: 1409414
>>>>>
>>>>>  URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
>>>>>  Log:
>>>>>  MYFACES-3638 revert commit 1408993 to include later solution
>> without
>>>>>  refactoring.
>>>>>
>>>>>  Added:
>>>>>
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>>        - copied unchanged from r1408992,
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>>  Removed:
>>>>>
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
>>>>>
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
>>>>>
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
>>>>>
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
>>>>>
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
>>>>>
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
>>>>>  Modified:
>>>>>      myfaces/core/trunk/impl/   (props changed)
>>>>>
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>
>>>>>  Propchange: myfaces/core/trunk/impl/
>>>>>
>> ------------------------------------------------------------------------------
>>>>>  --- svn:ignore (original)
>>>>>  +++ svn:ignore Wed Nov 14 21:23:35 2012
>>>>>  @@ -7,7 +7,8 @@ target
>>>>>  *.iml
>>>>>  *.ipr
>>>>>  *.iws
>>>>>  -.idea
>>>>>  .settings
>>>>>  +
>>>>>  cobertura.ser
>>>>>  +
>>>>>  test-output
>>>>>
>>>>>  Modified:
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>  URL:
>>>>>
>> http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
>>>>>
>> ==============================================================================
>>>>>  ---
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>  (original)
>>>>>  +++
>>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>>  Wed Nov 14 21:23:35 2012
>>>>>  @@ -30,16 +30,21 @@ import java.security.AccessController;
>>>>>  import java.security.PrivilegedActionException;
>>>>>  import java.security.PrivilegedExceptionAction;
>>>>>  import java.util.ArrayList;
>>>>>  +import java.util.Arrays;
>>>>>  import java.util.HashMap;
>>>>>  import java.util.List;
>>>>>  import java.util.Map;
>>>>>  +import java.util.Random;
>>>>>  import java.util.logging.Level;
>>>>>  import java.util.logging.Logger;
>>>>>  import java.util.zip.GZIPInputStream;
>>>>>  import java.util.zip.GZIPOutputStream;
>>>>>  +import javax.faces.application.ProjectStage;
>>>>>
>>>>>  import javax.faces.context.ExternalContext;
>>>>>  import javax.faces.context.FacesContext;
>>>>>  +import org.apache.commons.codec.DecoderException;
>>>>>  +import org.apache.commons.codec.binary.Hex;
>>>>>
>>>>>  import org.apache.commons.collections.map.AbstractReferenceMap;
>>>>>  import org.apache.commons.collections.map.ReferenceMap;
>>>>>  @@ -52,22 +57,22 @@ import org.apache.myfaces.shared.util.We
>>>>>  class ServerSideStateCacheImpl extends StateCache<Object,
>> Object>
>>>>>  {
>>>>>       private static final Logger log =
>>>>>  Logger.getLogger(ServerSideStateCacheImpl.class.getName());
>>>>>  -
>>>>>  -    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>>>>  +
>>>>>  +    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>>>>           ServerSideStateCacheImpl.class.getName() +
>>>>>  ".SERIALIZED_VIEW";
>>>>>  -
>>>>>  -    private static final String
>> RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>>>  +
>>>>>  +    private static final String
>> RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>>>           ServerSideStateCacheImpl.class.getName() +
>>>>>  ".RESTORED_SERIALIZED_VIEW";
>>>>>
>>>>>  -    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>>  +    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>>           ServerSideStateCacheImpl.class.getName() +
>>>>>  ".RESTORED_VIEW_KEY";
>>>>>  -
>>>>>  +
>>>>>       /**
>>>>>        * Defines the amount (default = 20) of the latest views are
>> stored in
>>>>>  session.
>>>>>  -     *
>>>>>  +     *
>>>>>        * <p>Only applicable if state saving method is
>> "server" (=
>>>>>  default).
>>>>>        * </p>
>>>>>  -     *
>>>>>  +     *
>>>>>        */
>>>>>
>> @JSFWebConfigParam(defaultValue="20",since="1.1",
>>>>>  classType="java.lang.Integer", group="state",
>>>>>  tags="performance")
>>>>>       private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM =
>>>>>  "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
>>>>>  @@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
>>>>>       /**
>>>>>        * 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>Only applicable if state saving method is
>> "server" (=
>>>>>  default). For example, if this param has value = 2 and
>>>>>  +     *
>>>>>  +     * <p>Only applicable if state saving method is
>> "server" (=
>>>>>  default). 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
>>>>>  @@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends S
>>>>>       @JSFWebConfigParam(since="2.0.6",
>>>>>  classType="java.lang.Integer", group="state",
>>>>>  tags="performance")
>>>>>       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;
>>>>>
>>>>>       /**
>>>>>  -     * Indicate if the state should be serialized before save it
>> on the
>>>>>  session.
>>>>>  +     * Indicate if the state should be serialized before save it
>> on the
>>>>>  session.
>>>>>        * <p>
>>>>>        * 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.
>>>>>  @@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends S
>>>>>
>>>>>       /**
>>>>>        * Indicates that the serialized state will be compressed
>> before it is
>>>>>  written to the session. By default true.
>>>>>  -     *
>>>>>  +     *
>>>>>        * 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.
>>>>>  @@ -140,38 +145,38 @@ class ServerSideStateCacheImpl extends S
>>>>>        * <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>
>>>>>  +     * <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",
>> group="state",
>>>>>  tags="performance")
>>>>>       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
>>>>>  +     * 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";
>>>>>
>>>>>       /**
>>>>>        * 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.
>>>>>  -     *
>>>>>  +     *
>>>>>        * <p>
>>>>>        * Only applicable if state saving method is
>> "server" (=
>>>>>  default).
>>>>>        * The default value is false.</p>
>>>>>  @@ -183,84 +188,90 @@ class ServerSideStateCacheImpl extends S
>>>>>       private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE =
>>>>>  "none";
>>>>>       private static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM =
>> "secureRandom";
>>>>>       private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM =
>>>>>  "random";
>>>>>  -
>>>>>  +
>>>>>       /**
>>>>>        * Adds a random key to the generated view state session
>> token.
>>>>>        */
>>>>>  -    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>  expectedValues="secureRandom, random, none",
>>>>>  +    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>  expectedValues="secureRandom, random, none",
>>>>>               defaultValue="none",
>> group="state")
>>>>>       private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
>>>>>               =
>>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
>>>>>  -    private static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>>  +    private static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>>               RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
>>>>>
>>>>>       /**
>>>>>        * Set the default length of the random key added to the view
>> state session
>>>>>  token.
>>>>>  -     * By default is 8.
>>>>>  +     * By default is 8.
>>>>>        */
>>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>  defaultValue="8", group="state")
>>>>>  -    static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>>  +    private static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>>               =
>>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
>>>>>  -    static final int
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>>  +    private static final int
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>>
>>>>>       /**
>>>>>  -     * Sets the random class to initialize the secure random id
>> generator.
>>>>>  +     * Sets the random class to initialize the secure random id
>> generator.
>>>>>        * By default it uses java.security.SecureRandom
>>>>>        */
>>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>  group="state")
>>>>>  -    static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>>  +    private static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>>               =
>>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
>>>>>  -
>>>>>  +
>>>>>       /**
>>>>>        * Sets the random provider to initialize the secure random id
>> generator.
>>>>>        */
>>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>  group="state")
>>>>>  -    static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>>  +    private static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>>               =
>>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
>>>>>  -
>>>>>  +
>>>>>       /**
>>>>>  -     * Sets the random algorithm to initialize the secure random
>> id generator.
>>>>>  +     * Sets the random algorithm to initialize the secure random
>> id generator.
>>>>>        * By default is SHA1PRNG
>>>>>        */
>>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>>  defaultValue="SHA1PRNG", group="state")
>>>>>  -    static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>>  +    private static final String
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>>               =
>>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
>>>>>  -
>>>>>  -
>>>>>  +
>>>>>  +
>>>>>       private static final int UNCOMPRESSED_FLAG = 0;
>>>>>       private static final int COMPRESSED_FLAG = 1;
>>>>>  -
>>>>>  +
>>>>>       private static final Object[] EMPTY_STATES = new
>> Object[]{null, null};
>>>>>
>>>>>  +    //private static final int JSF_SEQUENCE_INDEX = 0;
>>>>>  +
>>>>>       private Boolean _useFlashScopePurgeViewsInSession = null;
>>>>>  -
>>>>>  +
>>>>>       private Integer _numberOfSequentialViewsInSession = null;
>>>>>       private boolean _numberOfSequentialViewsInSessionSet = false;
>>>>>
>>>>>  +    //private final KeyFactory keyFactory;
>>>>>       private SessionViewStorageFactory sessionViewStorageFactory;
>>>>>
>>>>>       public ServerSideStateCacheImpl()
>>>>>       {
>>>>>           FacesContext facesContext =
>> FacesContext.getCurrentInstance();
>>>>>           String randomMode =
>>>>>
>> WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
>>>>>  -                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>>  +                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
>>>>>           if
>>>>>
>> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
>>>>>           {
>>>>>  -            sessionViewStorageFactory = new
>> SessionViewStorageFactory(
>>>>>  +            //keyFactory = new
>> SecureRandomKeyFactory(facesContext);
>>>>>  +            sessionViewStorageFactory = new
>> RandomSessionViewStorageFactory(
>>>>>                       new SecureRandomKeyFactory(facesContext));
>>>>>           }
>>>>>           else if
>>>>>  (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
>>>>>           {
>>>>>  -            sessionViewStorageFactory = new
>> SessionViewStorageFactory(
>>>>>  +            //keyFactory = new RandomKeyFactory(facesContext);
>>>>>  +            sessionViewStorageFactory = new
>> RandomSessionViewStorageFactory(
>>>>>                       new RandomKeyFactory(facesContext));
>>>>>           }
>>>>>           else
>>>>>           {
>>>>>  -            sessionViewStorageFactory = new
>> SessionViewStorageFactory(new
>>>>>  CounterKeyFactory());
>>>>>  +            //keyFactory = new CounterKeyFactory();
>>>>>  +            sessionViewStorageFactory = new
>>>>>  CounterSessionViewStorageFactory(new CounterKeyFactory());
>>>>>           }
>>>>>       }
>>>>>  -
>>>>>  +
>>>>>       //------------------------------------- METHODS COPIED FROM
>>>>>  JspStateManagerImpl--------------------------------
>>>>>
>>>>>       protected Object getServerStateId(FacesContext facesContext,
>> Object state)
>>>>>  @@ -285,16 +296,16 @@ class ServerSideStateCacheImpl extends S
>>>>>           }
>>>>>
>>>>>           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())
>> &&
>>>>>  +                if
>>>>>  (isUseFlashScopePurgeViewsInSession(context.getExternalContext())
>> &&
>>>>>
>>>>>  Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
>>>>>
>>>>>  .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
>>>>>                   {
>>>>>  @@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends S
>>>>>                   }
>>>>>               }
>>>>>           }
>>>>>  -
>>>>>  +
>>>>>           SerializedViewKey nextKey =
>>>>>  getSessionViewStorageFactory().createSerializedViewKey(
>>>>>                   context, context.getViewRoot().getViewId(),
>>>>>  getNextViewSequence(context));
>>>>>           viewCollection.add(context, serializeView(context,
>> serializedView),
>>>>>  nextKey, key);
>>>>>  @@ -339,14 +350,14 @@ class ServerSideStateCacheImpl extends S
>>>>>                   }
>>>>>               }
>>>>>
>> attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR,
>>>>>  serializedView);
>>>>>  -
>>>>>  +
>>>>>               if
>> (getNumberOfSequentialViewsInSession(externalContext) != null
>>>>>  &&
>>>>>
>> getNumberOfSequentialViewsInSession(externalContext) > 0)
>>>>>               {
>>>>>                   SerializedViewKey key =
>> getSessionViewStorageFactory().
>>>>>                           createSerializedViewKey(context, viewId,
>> sequence);
>>>>>                   attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR,
>> key);
>>>>>  -
>>>>>  +
>>>>>                   if
>> (isUseFlashScopePurgeViewsInSession(externalContext))
>>>>>                   {
>>>>>
>>>>>  externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR,
>> key);
>>>>>  @@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends S
>>>>>                   //Object[] stateArray = (Object[]) serializedView;
>>>>>
>>>>>                   ObjectOutputStream out = new
>> ObjectOutputStream(os);
>>>>>  -
>>>>>  +
>>>>>                   out.writeObject(serializedView);
>>>>>                   //out.writeObject(stateArray[0]);
>>>>>                   //out.writeObject(stateArray[1]);
>>>>>  @@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends S
>>>>>                       final ObjectInputStream in = new
>>>>>  MyFacesObjectInputStream(is);
>>>>>                       ois = in;
>>>>>                       Object object = null;
>>>>>  -                    if (System.getSecurityManager() != null)
>>>>>  +                    if (System.getSecurityManager() != null)
>>>>>                       {
>>>>>  -                        object = AccessController.doPrivileged(new
>>>>>  PrivilegedExceptionAction<Object>()
>>>>>  +                        object = AccessController.doPrivileged(new
>>>>>  PrivilegedExceptionAction<Object>()
>>>>>                           {
>>>>>                               public Object run() throws
>>>>>  PrivilegedActionException, IOException, ClassNotFoundException
>>>>>                               {
>>>>>  @@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends S
>>>>>                       }
>>>>>                   }
>>>>>               }
>>>>>  -            catch (PrivilegedActionException e)
>>>>>  +            catch (PrivilegedActionException e)
>>>>>               {
>>>>>                   log.log(Level.SEVERE, "Exiting
>> deserializeView - Could not
>>>>>  deserialize state: " + e.getMessage(), e);
>>>>>                   return null;
>>>>>  @@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends S
>>>>>               return null;
>>>>>           }
>>>>>       }
>>>>>  -
>>>>>  +
>>>>>       protected static class SerializedViewCollection implements
>> Serializable
>>>>>       {
>>>>>           private static final long serialVersionUID =
>> -3734849062185115847L;
>>>>>  @@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends S
>>>>>           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 =
>>>>>  +
>>>>>  +        private final Map<SerializedViewKey,
>> SerializedViewKey>
>>>>>  _precedence =
>>>>>               new HashMap<SerializedViewKey,
>> SerializedViewKey>();
>>>>>
>>>>>           // old views will be hold as soft references which will be
>> removed by
>>>>>  @@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends S
>>>>>                   // into the map.
>>>>>                   state = null;
>>>>>               }
>>>>>  -
>>>>>  +
>>>>>               Integer maxCount =
>> getNumberOfSequentialViewsInSession(context);
>>>>>               if (maxCount != null)
>>>>>               {
>>>>>  @@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends S
>>>>>                     previousKey = _precedence.get(previousKey);
>>>>>                     count++;
>>>>>                   } while (previousKey != null && count <
>> maxCount);
>>>>>  -
>>>>>  +
>>>>>                   if (previousKey != null)
>>>>>                   {
>>>>>                       SerializedViewKey keyToRemove =
>> (SerializedViewKey)
>>>>>  previousKey;
>>>>>  @@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends S
>>>>>                           {
>>>>>                               _serializedViews.remove(keyToRemove);
>>>>>                           }
>>>>>  -
>>>>>  +
>>>>>                           keyToRemove =
>> _precedence.remove(keyToRemove);
>>>>>                       }  while(keyToRemove != null);
>>>>>                   }
>>>>>  @@ -680,11 +691,11 @@ class ServerSideStateCacheImpl extends S
>>>>>               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,
>>>>>  +                    // 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
>>>>>  @@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends S
>>>>>                   if (_serializedViews.containsKey(key) &&
>>>>>
>>>>>
>> !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
>>>>>                   {
>>>>>  -
>>>>>  +
>>>>>                       getOldSerializedViewsMap().put(key,
>>>>>  _serializedViews.remove(key));
>>>>>                   }
>>>>>                   else
>>>>>  @@ -708,10 +719,10 @@ class ServerSideStateCacheImpl extends S
>>>>>
>>>>>           protected Integer
>> getNumberOfSequentialViewsInSession(FacesContext
>>>>>  context)
>>>>>           {
>>>>>  -            return
>>>>>
>> WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
>>>>>  +            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
>>>>>  @@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends S
>>>>>               FacesContext context =
>> FacesContext.getCurrentInstance();
>>>>>               if (_oldSerializedViews == null && context !=
>> null)
>>>>>               {
>>>>>  -                String cacheMode =
>> getCacheOldViewsInSessionMode(context);
>>>>>  +                String cacheMode =
>> getCacheOldViewsInSessionMode(context);
>>>>>                   if
>> (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
>>>>>                   {
>>>>>                       _oldSerializedViews = new
>>>>>  ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK,
>> true);
>>>>>  @@ -773,13 +784,13 @@ class ServerSideStateCacheImpl extends S
>>>>>                       _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
>>>>>  @@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends S
>>>>>               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;
>>>>>  @@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends S
>>>>>                   return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
>>>>>               }
>>>>>           }
>>>>>  -
>>>>>  +
>>>>>           public Object get(SerializedViewKey key)
>>>>>           {
>>>>>               Object value = _serializedViews.get(key);
>>>>>  @@ -846,7 +857,172 @@ class ServerSideStateCacheImpl extends S
>>>>>           }
>>>>>       }
>>>>>
>>>>>  +    /**
>>>>>  +     * Base implementation where all keys used to identify the
>> state of a view
>>>>>  should
>>>>>  +     * extend.
>>>>>  +     */
>>>>>  +    protected abstract static class SerializedViewKey implements
>> Serializable
>>>>>  +    {
>>>>>  +    }
>>>>>  +
>>>>>  +    /**
>>>>>  +     * Implementation of SerializedViewKey, where the hashCode of
>> the viewId is
>>>>>  used
>>>>>  +     * and the sequenceId is a numeric value.
>>>>>  +     */
>>>>>  +    private static class IntIntSerializedViewKey extends
>> SerializedViewKey
>>>>>  +        implements Serializable
>>>>>  +    {
>>>>>  +        private static final long serialVersionUID =
>> -1170697124386063642L;
>>>>>  +
>>>>>  +        private final int _viewId;
>>>>>  +        private final int _sequenceId;
>>>>>  +
>>>>>  +        public IntIntSerializedViewKey(int viewId, int sequence)
>>>>>  +        {
>>>>>  +            _sequenceId = sequence;
>>>>>  +            _viewId = viewId;
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public boolean equals(Object obj)
>>>>>  +        {
>>>>>  +            if (obj == null)
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            if (getClass() != obj.getClass())
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            final IntIntSerializedViewKey other =
>> (IntIntSerializedViewKey)
>>>>>  obj;
>>>>>  +            if (this._viewId != other._viewId)
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            if (this._sequenceId != other._sequenceId)
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            return true;
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public int hashCode()
>>>>>  +        {
>>>>>  +            int hash = 7;
>>>>>  +            hash = 83 * hash + this._viewId;
>>>>>  +            hash = 83 * hash + this._sequenceId;
>>>>>  +            return hash;
>>>>>  +        }
>>>>>  +    }
>>>>>  +
>>>>>  +    /**
>>>>>  +     * Implementation of SerializedViewKey, where the hashCode of
>> the viewId is
>>>>>  used
>>>>>  +     * and the sequenceId is a string value.
>>>>>  +     */
>>>>>  +    private static class IntByteArraySerializedViewKey extends
>>>>>  SerializedViewKey
>>>>>  +        implements Serializable
>>>>>  +    {
>>>>>  +        private final int _viewId;
>>>>>  +        private final byte[] _sequenceId;
>>>>>  +
>>>>>  +        public IntByteArraySerializedViewKey(int viewId, byte[]
>> sequence)
>>>>>  +        {
>>>>>  +            _sequenceId = sequence;
>>>>>  +            _viewId = viewId;
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public boolean equals(Object obj)
>>>>>  +        {
>>>>>  +            if (obj == null)
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            if (getClass() != obj.getClass())
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            final IntByteArraySerializedViewKey other =
>>>>>  (IntByteArraySerializedViewKey) obj;
>>>>>  +            if (this._viewId != other._viewId)
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            if (!Arrays.equals(this._sequenceId,
>> other._sequenceId))
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            return true;
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public int hashCode()
>>>>>  +        {
>>>>>  +            int hash = 5;
>>>>>  +            hash = 37 * hash + this._viewId;
>>>>>  +            hash = 37 * hash + Arrays.hashCode(this._sequenceId);
>>>>>  +            return hash;
>>>>>  +        }
>>>>>  +    }
>>>>>  +
>>>>>  +
>>>>>  +    /**
>>>>>  +     * Implementation of SerializedViewKey, where the viewId and
>> the sequenceId
>>>>>  can be
>>>>>  +     * anything.
>>>>>  +     */
>>>>>  +    private static class ReferenceSerializedViewKey<I,K>
>> extends
>>>>>  SerializedViewKey
>>>>>  +        implements Serializable
>>>>>  +    {
>>>>>  +        private static final long serialVersionUID =
>> -1170697124386063642L;
>>>>>  +
>>>>>  +        private final I _viewId;
>>>>>  +        private final K _sequenceId;
>>>>>
>>>>>  +        public ReferenceSerializedViewKey()
>>>>>  +        {
>>>>>  +            _sequenceId = null;
>>>>>  +            _viewId = null;
>>>>>  +        }
>>>>>  +        public ReferenceSerializedViewKey(I viewId, K sequence)
>>>>>  +        {
>>>>>  +            _sequenceId = sequence;
>>>>>  +            _viewId = viewId;
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public boolean equals(Object obj)
>>>>>  +        {
>>>>>  +            if (obj == null)
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            if (getClass() != obj.getClass())
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            final ReferenceSerializedViewKey<I, K> other =
>>>>>  (ReferenceSerializedViewKey<I, K>) obj;
>>>>>  +            if (this._viewId != other._viewId &&
>> (this._viewId == null
>>>>>  || !this._viewId.equals(other._viewId)))
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            if (this._sequenceId != other._sequenceId &&
>>>>>  +                (this._sequenceId == null ||
>>>>>  !this._sequenceId.equals(other._sequenceId)))
>>>>>  +            {
>>>>>  +                return false;
>>>>>  +            }
>>>>>  +            return true;
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public int hashCode()
>>>>>  +        {
>>>>>  +            int hash = 7;
>>>>>  +            hash = 83 * hash + (this._viewId != null ?
>> this._viewId.hashCode()
>>>>>  : 0);
>>>>>  +            hash = 83 * hash + (this._sequenceId != null ?
>>>>>  this._sequenceId.hashCode() : 0);
>>>>>  +            return hash;
>>>>>  +        }
>>>>>  +    }
>>>>>  +
>>>>>       //------------------------------------- METHOD FROM StateCache
>>>>>  ------------------------------------------------
>>>>>
>>>>>       @Override
>>>>>  @@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl extends S
>>>>>           }
>>>>>           //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);
>>>>>       }
>>>>>
>>>>>  @@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl extends S
>>>>>       {
>>>>>           return
>>>>>
>> getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
>>>>>       }
>>>>>  -
>>>>>  +
>>>>>       @Override
>>>>>       public boolean
>> isWriteStateAfterRenderViewRequired(FacesContext
>>>>>  facesContext)
>>>>>       {
>>>>>  @@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl extends S
>>>>>       }
>>>>>
>>>>>       //------------------------------------- Custom methods
>>>>>  -----------------------------------------------------
>>>>>  -
>>>>>  +
>>>>>       private boolean
>> isUseFlashScopePurgeViewsInSession(ExternalContext
>>>>>  externalContext)
>>>>>       {
>>>>>           if (_useFlashScopePurgeViewsInSession == null)
>>>>>  @@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl extends S
>>>>>           }
>>>>>           return _useFlashScopePurgeViewsInSession;
>>>>>       }
>>>>>  -
>>>>>  +
>>>>>       private Integer
>> getNumberOfSequentialViewsInSession(ExternalContext
>>>>>  externalContext)
>>>>>       {
>>>>>           if (!_numberOfSequentialViewsInSessionSet)
>>>>>           {
>>>>>               _numberOfSequentialViewsInSession =
>>>>>  WebConfigParamUtils.getIntegerInitParameter(
>>>>>  -                    externalContext,
>>>>>  +                    externalContext,
>>>>>                       NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
>>>>>               _numberOfSequentialViewsInSessionSet = true;
>>>>>           }
>>>>>           return _numberOfSequentialViewsInSession;
>>>>>       }
>>>>>  -
>>>>>  +
>>>>>       protected KeyFactory getKeyFactory(FacesContext facesContext)
>>>>>       {
>>>>>           //return keyFactory;
>>>>>           return sessionViewStorageFactory.getKeyFactory();
>>>>>       }
>>>>>  -
>>>>>  +
>>>>>       protected SessionViewStorageFactory
>> getSessionViewStorageFactory()
>>>>>       {
>>>>>           return sessionViewStorageFactory;
>>>>>       }
>>>>>  +
>>>>>
>>>>>  +    protected abstract static class KeyFactory<K, V>
>>>>>  +    {
>>>>>  +
>>>>>  +        /**
>>>>>  +         * Generates a unique key per session
>>>>>  +         *
>>>>>  +         * @param facesContext
>>>>>  +         * @return
>>>>>  +         */
>>>>>  +        public abstract K generateKey(FacesContext facesContext);
>>>>>  +
>>>>>  +        /**
>>>>>  +         * Encode a Key into a value that will be used as view
>> state session
>>>>>  token
>>>>>  +         *
>>>>>  +         * @param key
>>>>>  +         * @return
>>>>>  +         */
>>>>>  +        public abstract V encode(K key);
>>>>>
>>>>>  +        /**
>>>>>  +         * Decode a view state session token into a key
>>>>>  +         *
>>>>>  +         * @param value
>>>>>  +         * @return
>>>>>  +         */
>>>>>  +        public abstract K decode(V value);
>>>>>  +
>>>>>  +    }
>>>>>  +
>>>>>  +    private static class CounterKeyFactory extends
>> KeyFactory<Integer,
>>>>>  String>
>>>>>  +    {
>>>>>  +        /**
>>>>>  +         * Take the counter from session scope and increment
>>>>>  +         *
>>>>>  +         * @param facesContext
>>>>>  +         * @return
>>>>>  +         */
>>>>>  +        @Override
>>>>>  +        public Integer generateKey(FacesContext facesContext)
>>>>>  +        {
>>>>>  +            ExternalContext externalContext =
>>>>>  facesContext.getExternalContext();
>>>>>  +            Object sessionObj = externalContext.getSession(true);
>>>>>  +            Integer sequence = null;
>>>>>  +            synchronized(sessionObj) // synchronized to increase
>> sequence if
>>>>>  multiple requests
>>>>>  +                                    // are handled at the same
>> time for the
>>>>>  session
>>>>>  +            {
>>>>>  +                Map<String, Object> map =
>>>>>  externalContext.getSessionMap();
>>>>>  +                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);
>>>>>  +            }
>>>>>  +            return sequence;
>>>>>  +        }
>>>>>  +
>>>>>  +        public String encode(Integer sequence)
>>>>>  +        {
>>>>>  +            return Integer.toString(sequence,
>> Character.MAX_RADIX);
>>>>>  +        }
>>>>>  +
>>>>>  +        public Integer decode(String serverStateId)
>>>>>  +        {
>>>>>  +             return Integer.valueOf((String) serverStateId,
>>>>>  Character.MAX_RADIX);
>>>>>  +        }
>>>>>  +    }
>>>>>  +
>>>>>  +    /**
>>>>>  +     * This factory generate a key composed by a counter and a
>> random number.
>>>>>  The
>>>>>  +     * counter ensures uniqueness, and the random number prevents
>> guess the
>>>>>  next
>>>>>  +     * session token.
>>>>>  +     */
>>>>>  +    private static class SecureRandomKeyFactory extends
>> KeyFactory<byte[],
>>>>>  String>
>>>>>  +    {
>>>>>  +        private final SessionIdGenerator sessionIdGenerator;
>>>>>  +        private final int length;
>>>>>  +
>>>>>  +        public SecureRandomKeyFactory(FacesContext facesContext)
>>>>>  +        {
>>>>>  +            length =
>>>>>
>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>>  +
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>>  +
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>>  +            sessionIdGenerator = new SessionIdGenerator();
>>>>>  +            sessionIdGenerator.setSessionIdLength(length);
>>>>>  +            String secureRandomClass =
>>>>>  WebConfigParamUtils.getStringInitParameter(
>>>>>  +                    facesContext.getExternalContext(),
>>>>>  +
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
>>>>>  +            if (secureRandomClass != null)
>>>>>  +            {
>>>>>  +
>> sessionIdGenerator.setSecureRandomClass(secureRandomClass);
>>>>>  +            }
>>>>>  +            String secureRandomProvider =
>>>>>  WebConfigParamUtils.getStringInitParameter(
>>>>>  +                    facesContext.getExternalContext(),
>>>>>  +
>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
>>>>>  +            if (secureRandomProvider != null)
>>>>>  +            {
>>>>>  +
>>>>>  sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
>>>>>  +            }
>>>>>  +            String secureRandomAlgorithm =
>>>>>  WebConfigParamUtils.getStringInitParameter(
>>>>>  +                    facesContext.getExternalContext(),
>>>>>  +
>>>>>
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
>>>>>  +            if (secureRandomAlgorithm != null)
>>>>>  +            {
>>>>>  +
>>>>>  sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
>>>>>  +            }
>>>>>  +        }
>>>>>  +
>>>>>  +        public Integer generateCounterKey(FacesContext
>> facesContext)
>>>>>  +        {
>>>>>  +            ExternalContext externalContext =
>>>>>  facesContext.getExternalContext();
>>>>>  +            Object sessionObj = externalContext.getSession(true);
>>>>>  +            Integer sequence = null;
>>>>>  +            synchronized(sessionObj) // synchronized to increase
>> sequence if
>>>>>  multiple requests
>>>>>  +                                    // are handled at the same
>> time for the
>>>>>  session
>>>>>  +            {
>>>>>  +                Map<String, Object> map =
>>>>>  externalContext.getSessionMap();
>>>>>  +                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);
>>>>>  +            }
>>>>>  +            return sequence;
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public byte[] generateKey(FacesContext facesContext)
>>>>>  +        {
>>>>>  +            byte[] array = new byte[length];
>>>>>  +            byte[] key = new byte[length+4];
>>>>>  +
>>>>>  +            sessionIdGenerator.getRandomBytes(array);
>>>>>  +            for (int i = 0; i < array.length; i++)
>>>>>  +            {
>>>>>  +                key[i] = array[i];
>>>>>  +            }
>>>>>  +            int value = generateCounterKey(facesContext);
>>>>>  +            key[array.length] =  (byte) (value >>> 24);
>>>>>  +            key[array.length+1] =  (byte) (value >>> 16);
>>>>>  +            key[array.length+2] =  (byte) (value >>> 8);
>>>>>  +            key[array.length+3] =  (byte) (value);
>>>>>  +
>>>>>  +            return key;
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public String encode(byte[] key)
>>>>>  +        {
>>>>>  +            return new String(Hex.encodeHex(key));
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public byte[] decode(String value)
>>>>>  +        {
>>>>>  +            try
>>>>>  +            {
>>>>>  +                return Hex.decodeHex(value.toCharArray());
>>>>>  +            }
>>>>>  +            catch (DecoderException ex)
>>>>>  +            {
>>>>>  +                // Cannot decode, ignore silently, later it will
>> be handled as
>>>>>  +                // ViewExpiredException
>>>>>  +            }
>>>>>  +            return null;
>>>>>  +        }
>>>>>  +    }
>>>>>  +
>>>>>  +    private static class RandomKeyFactory extends
>> KeyFactory<byte[],
>>>>>  String>
>>>>>  +    {
>>>>>  +        private final Random random;
>>>>>  +        private final int length;
>>>>>  +
>>>>>  +        public RandomKeyFactory(FacesContext facesContext)
>>>>>  +        {
>>>>>  +            length =
>>>>>
>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>>  +
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>>  +
>>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>>  +            random = new
>> Random(((int)System.nanoTime())+this.hashCode());
>>>>>  +        }
>>>>>  +
>>>>>  +        public Integer generateCounterKey(FacesContext
>> facesContext)
>>>>>  +        {
>>>>>  +            ExternalContext externalContext =
>>>>>  facesContext.getExternalContext();
>>>>>  +            Object sessionObj = externalContext.getSession(true);
>>>>>  +            Integer sequence = null;
>>>>>  +            synchronized(sessionObj) // synchronized to increase
>> sequence if
>>>>>  multiple requests
>>>>>  +                                    // are handled at the same
>> time for the
>>>>>  session
>>>>>  +            {
>>>>>  +                Map<String, Object> map =
>>>>>  externalContext.getSessionMap();
>>>>>  +                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);
>>>>>  +            }
>>>>>  +            return sequence;
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public byte[] generateKey(FacesContext facesContext)
>>>>>  +        {
>>>>>  +            byte[] array = new byte[length];
>>>>>  +            byte[] key = new byte[length+4];
>>>>>  +
>>>>>  +            //sessionIdGenerator.getRandomBytes(array);
>>>>>  +            random.nextBytes(array);
>>>>>  +            for (int i = 0; i < array.length; i++)
>>>>>  +            {
>>>>>  +                key[i] = array[i];
>>>>>  +            }
>>>>>  +            int value = generateCounterKey(facesContext);
>>>>>  +            key[array.length] =  (byte) (value >>> 24);
>>>>>  +            key[array.length+1] =  (byte) (value >>> 16);
>>>>>  +            key[array.length+2] =  (byte) (value >>> 8);
>>>>>  +            key[array.length+3] =  (byte) (value);
>>>>>  +
>>>>>  +            return key;
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public String encode(byte[] key)
>>>>>  +        {
>>>>>  +            return new String(Hex.encodeHex(key));
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public byte[] decode(String value)
>>>>>  +        {
>>>>>  +            try
>>>>>  +            {
>>>>>  +                return Hex.decodeHex(value.toCharArray());
>>>>>  +            }
>>>>>  +            catch (DecoderException ex)
>>>>>  +            {
>>>>>  +                // Cannot decode, ignore silently, later it will
>> be handled as
>>>>>  +                // ViewExpiredException
>>>>>  +            }
>>>>>  +            return null;
>>>>>  +        }
>>>>>  +    }
>>>>>  +
>>>>>  +    /**
>>>>>  +     *
>>>>>  +     * @param <T>
>>>>>  +     * @param <K>
>>>>>  +     * @param <V>
>>>>>  +     */
>>>>>  +    protected abstract static class SessionViewStorageFactory
>> <T extends
>>>>>  KeyFactory<K,V>, K, V >
>>>>>  +    {
>>>>>  +        private KeyFactory<K, V> keyFactory;
>>>>>  +
>>>>>  +        public SessionViewStorageFactory(KeyFactory<K, V>
>> keyFactory)
>>>>>  +        {
>>>>>  +            this.keyFactory = keyFactory;
>>>>>  +        }
>>>>>  +
>>>>>  +        public KeyFactory<K, V> getKeyFactory()
>>>>>  +        {
>>>>>  +            return keyFactory;
>>>>>  +        }
>>>>>  +
>>>>>  +        public abstract SerializedViewCollection
>>>>>  createSerializedViewCollection(
>>>>>  +                FacesContext context);
>>>>>  +
>>>>>  +        public abstract SerializedViewKey createSerializedViewKey(
>>>>>  +                FacesContext facesContext, String viewId, K key);
>>>>>  +
>>>>>  +    }
>>>>>  +
>>>>>  +    private static class CounterSessionViewStorageFactory
>>>>>  +        extends SessionViewStorageFactory <KeyFactory
>>>>>  <Integer,String>, Integer, String>
>>>>>  +    {
>>>>>  +        public
>> CounterSessionViewStorageFactory(KeyFactory<Integer,
>>>>>  String> keyFactory)
>>>>>  +        {
>>>>>  +            super(keyFactory);
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public SerializedViewCollection
>> createSerializedViewCollection(
>>>>>  +                FacesContext context)
>>>>>  +        {
>>>>>  +            return new SerializedViewCollection();
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public SerializedViewKey createSerializedViewKey(
>>>>>  +                FacesContext context, String viewId, Integer key)
>>>>>  +        {
>>>>>  +            if (context.isProjectStage(ProjectStage.Production))
>>>>>  +            {
>>>>>  +                return new
>> IntIntSerializedViewKey(viewId.hashCode(), key);
>>>>>  +            }
>>>>>  +            else
>>>>>  +            {
>>>>>  +                return new ReferenceSerializedViewKey(viewId,
>> key);
>>>>>  +            }
>>>>>  +        }
>>>>>  +    }
>>>>>  +
>>>>>  +    private static class RandomSessionViewStorageFactory
>>>>>  +        extends SessionViewStorageFactory <KeyFactory
>> <byte[],String>,
>>>>>  byte[], String>
>>>>>  +    {
>>>>>  +        public
>> RandomSessionViewStorageFactory(KeyFactory<byte[], String>
>>>>>  keyFactory)
>>>>>  +        {
>>>>>  +            super(keyFactory);
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public SerializedViewCollection
>> createSerializedViewCollection(
>>>>>  +                FacesContext context)
>>>>>  +        {
>>>>>  +            return new SerializedViewCollection();
>>>>>  +        }
>>>>>  +
>>>>>  +        @Override
>>>>>  +        public SerializedViewKey createSerializedViewKey(
>>>>>  +                FacesContext context, String viewId, byte[] key)
>>>>>  +        {
>>>>>  +            if (context.isProjectStage(ProjectStage.Production))
>>>>>  +            {
>>>>>  +                return new
>> IntByteArraySerializedViewKey(viewId.hashCode(),
>>>>>  key);
>>>>>  +            }
>>>>>  +            else
>>>>>  +            {
>>>>>  +                return new ReferenceSerializedViewKey(viewId,
>> key);
>>>>>  +            }
>>>>>  +        }
>>>>>  +    }
>>>>>  }
>>>>>
>>

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Mark Struberg <st...@yahoo.de>.



Leo we HAD that already in production (with an IBM JVM). Does that count?

using the hashCode to speed up caches is perfectly fine. But only for _excluding_ matches, Getting the same hashCode doesn't make sure something is unique.

Also in the private mail you pointed to an example yourself [1]:


[1] pry(main)> "a".hash
=> 100 [2] pry(main)> "\0a".hash
=> 100 [3] pry(main)> "\0\0a".hash
=> 100 [4] pry(main)> "\0\0\0a".hash
=> 100 [5] pry(main)> "\0\0\0\0a".hash
=> 100 [6] pry(main)> "\0\0\0\0\0a".hash
=> 100

It's just not guaranteed.

LieGrue,
strub



[1] http://martin.kleppmann.com/2012/06/18/java-hashcode-unsafe-for-distributed-systems.html



----- Original Message -----
> From: Leonardo Uribe <lu...@gmail.com>
> To: MyFaces Development <de...@myfaces.apache.org>; Mark Struberg <st...@yahoo.de>
> Cc: 
> Sent: Wednesday, November 14, 2012 11:34 PM
> Subject: Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/
> 
> 2012/11/14 Leonardo Uribe <lu...@gmail.com>:
>>  Hi
>> 
>>  2012/11/14 Mark Struberg <st...@yahoo.de>:
>>>  Leo, there was a reason I removed it.
>>> 
>>> 
>>>  Even after discussing this over 10 mails in a private thread you 
> don't get it it seems. I will open a VOTE about principal design 
> fundamentals and we will act according to this.
>>> 
>>>  Just you be prepated: A HASH IS NOT UNIQUE!
>>> 
>> 
>>  But I have told you multiple times, the algorithm does not rely on the
>>  hash to be unique, relies on the counter.
>> 
>>>  Also saying in the mails you understand and then doing the same crazy 
> code again is just plain ******
>>> 
>>>  I gonna revert it now and will write up the VOTE
>> 
>>  The best way to resolve this is putting the arguments on the table and
>>  vote over that, right? after the vote we can do the necessary changes
>>  over the code. I have committed the fix that I suppose is correct.
>> 
> 
> It is more, could you please try if the fix proposed by me works in your case?
> could you please show two viewIds that can be written as valid file names that
> has the same hashCode? I'm open to change my mind, but first I need
> concrete arguments to do that.
> 
>>  regards,
>> 
>>  Leonardo
>> 
>>> 
>>>  LieGrue,
>>>  strub
>>> 
>>> 
>>> 
>>> 
>>>  ----- Original Message -----
>>>>  From: "lu4242@apache.org" <lu...@apache.org>
>>>>  To: commits@myfaces.apache.org
>>>>  Cc:
>>>>  Sent: Wednesday, November 14, 2012 10:23 PM
>>>>  Subject: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ 
> src/main/java/org/apache/myfaces/renderkit/
>>>> 
>>>>  Author: lu4242
>>>>  Date: Wed Nov 14 21:23:35 2012
>>>>  New Revision: 1409414
>>>> 
>>>>  URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
>>>>  Log:
>>>>  MYFACES-3638 revert commit 1408993 to include later solution 
> without
>>>>  refactoring.
>>>> 
>>>>  Added:
>>>> 
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>        - copied unchanged from r1408992,
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>  Removed:
>>>> 
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
>>>> 
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
>>>> 
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
>>>> 
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
>>>> 
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
>>>> 
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
>>>>  Modified:
>>>>      myfaces/core/trunk/impl/   (props changed)
>>>> 
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>> 
>>>>  Propchange: myfaces/core/trunk/impl/
>>>> 
> ------------------------------------------------------------------------------
>>>>  --- svn:ignore (original)
>>>>  +++ svn:ignore Wed Nov 14 21:23:35 2012
>>>>  @@ -7,7 +7,8 @@ target
>>>>  *.iml
>>>>  *.ipr
>>>>  *.iws
>>>>  -.idea
>>>>  .settings
>>>>  +
>>>>  cobertura.ser
>>>>  +
>>>>  test-output
>>>> 
>>>>  Modified:
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>  URL:
>>>> 
> http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
>>>> 
> ==============================================================================
>>>>  ---
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>  (original)
>>>>  +++
>>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>  Wed Nov 14 21:23:35 2012
>>>>  @@ -30,16 +30,21 @@ import java.security.AccessController;
>>>>  import java.security.PrivilegedActionException;
>>>>  import java.security.PrivilegedExceptionAction;
>>>>  import java.util.ArrayList;
>>>>  +import java.util.Arrays;
>>>>  import java.util.HashMap;
>>>>  import java.util.List;
>>>>  import java.util.Map;
>>>>  +import java.util.Random;
>>>>  import java.util.logging.Level;
>>>>  import java.util.logging.Logger;
>>>>  import java.util.zip.GZIPInputStream;
>>>>  import java.util.zip.GZIPOutputStream;
>>>>  +import javax.faces.application.ProjectStage;
>>>> 
>>>>  import javax.faces.context.ExternalContext;
>>>>  import javax.faces.context.FacesContext;
>>>>  +import org.apache.commons.codec.DecoderException;
>>>>  +import org.apache.commons.codec.binary.Hex;
>>>> 
>>>>  import org.apache.commons.collections.map.AbstractReferenceMap;
>>>>  import org.apache.commons.collections.map.ReferenceMap;
>>>>  @@ -52,22 +57,22 @@ import org.apache.myfaces.shared.util.We
>>>>  class ServerSideStateCacheImpl extends StateCache<Object, 
> Object>
>>>>  {
>>>>       private static final Logger log =
>>>>  Logger.getLogger(ServerSideStateCacheImpl.class.getName());
>>>>  -
>>>>  -    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>>>  +
>>>>  +    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>>>           ServerSideStateCacheImpl.class.getName() +
>>>>  ".SERIALIZED_VIEW";
>>>>  -
>>>>  -    private static final String 
> RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>>  +
>>>>  +    private static final String 
> RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>>           ServerSideStateCacheImpl.class.getName() +
>>>>  ".RESTORED_SERIALIZED_VIEW";
>>>> 
>>>>  -    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>  +    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>           ServerSideStateCacheImpl.class.getName() +
>>>>  ".RESTORED_VIEW_KEY";
>>>>  -
>>>>  +
>>>>       /**
>>>>        * Defines the amount (default = 20) of the latest views are 
> stored in
>>>>  session.
>>>>  -     *
>>>>  +     *
>>>>        * <p>Only applicable if state saving method is 
> "server" (=
>>>>  default).
>>>>        * </p>
>>>>  -     *
>>>>  +     *
>>>>        */
>>>>       
> @JSFWebConfigParam(defaultValue="20",since="1.1",
>>>>  classType="java.lang.Integer", group="state",
>>>>  tags="performance")
>>>>       private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM =
>>>>  "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
>>>>  @@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
>>>>       /**
>>>>        * 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>Only applicable if state saving method is 
> "server" (=
>>>>  default). For example, if this param has value = 2 and
>>>>  +     *
>>>>  +     * <p>Only applicable if state saving method is 
> "server" (=
>>>>  default). 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
>>>>  @@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends S
>>>>       @JSFWebConfigParam(since="2.0.6",
>>>>  classType="java.lang.Integer", group="state",
>>>>  tags="performance")
>>>>       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;
>>>> 
>>>>       /**
>>>>  -     * Indicate if the state should be serialized before save it 
> on the
>>>>  session.
>>>>  +     * Indicate if the state should be serialized before save it 
> on the
>>>>  session.
>>>>        * <p>
>>>>        * 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.
>>>>  @@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends S
>>>> 
>>>>       /**
>>>>        * Indicates that the serialized state will be compressed 
> before it is
>>>>  written to the session. By default true.
>>>>  -     *
>>>>  +     *
>>>>        * 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.
>>>>  @@ -140,38 +145,38 @@ class ServerSideStateCacheImpl extends S
>>>>        * <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>
>>>>  +     * <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", 
> group="state",
>>>>  tags="performance")
>>>>       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
>>>>  +     * 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";
>>>> 
>>>>       /**
>>>>        * 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.
>>>>  -     *
>>>>  +     *
>>>>        * <p>
>>>>        * Only applicable if state saving method is 
> "server" (=
>>>>  default).
>>>>        * The default value is false.</p>
>>>>  @@ -183,84 +188,90 @@ class ServerSideStateCacheImpl extends S
>>>>       private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE =
>>>>  "none";
>>>>       private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM = 
> "secureRandom";
>>>>       private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM =
>>>>  "random";
>>>>  -
>>>>  +
>>>>       /**
>>>>        * Adds a random key to the generated view state session 
> token.
>>>>        */
>>>>  -    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  expectedValues="secureRandom, random, none",
>>>>  +    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  expectedValues="secureRandom, random, none",
>>>>               defaultValue="none", 
> group="state")
>>>>       private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
>>>>               =
>>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
>>>>  -    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>  +    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>               RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
>>>> 
>>>>       /**
>>>>        * Set the default length of the random key added to the view 
> state session
>>>>  token.
>>>>  -     * By default is 8.
>>>>  +     * By default is 8.
>>>>        */
>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  defaultValue="8", group="state")
>>>>  -    static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>  +    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>               =
>>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
>>>>  -    static final int
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>  +    private static final int
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>> 
>>>>       /**
>>>>  -     * Sets the random class to initialize the secure random id 
> generator.
>>>>  +     * Sets the random class to initialize the secure random id 
> generator.
>>>>        * By default it uses java.security.SecureRandom
>>>>        */
>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  group="state")
>>>>  -    static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>  +    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>               =
>>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
>>>>  -
>>>>  +
>>>>       /**
>>>>        * Sets the random provider to initialize the secure random id 
> generator.
>>>>        */
>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  group="state")
>>>>  -    static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>  +    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>               =
>>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
>>>>  -
>>>>  +
>>>>       /**
>>>>  -     * Sets the random algorithm to initialize the secure random 
> id generator.
>>>>  +     * Sets the random algorithm to initialize the secure random 
> id generator.
>>>>        * By default is SHA1PRNG
>>>>        */
>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  defaultValue="SHA1PRNG", group="state")
>>>>  -    static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>  +    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>               =
>>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
>>>>  -
>>>>  -
>>>>  +
>>>>  +
>>>>       private static final int UNCOMPRESSED_FLAG = 0;
>>>>       private static final int COMPRESSED_FLAG = 1;
>>>>  -
>>>>  +
>>>>       private static final Object[] EMPTY_STATES = new 
> Object[]{null, null};
>>>> 
>>>>  +    //private static final int JSF_SEQUENCE_INDEX = 0;
>>>>  +
>>>>       private Boolean _useFlashScopePurgeViewsInSession = null;
>>>>  -
>>>>  +
>>>>       private Integer _numberOfSequentialViewsInSession = null;
>>>>       private boolean _numberOfSequentialViewsInSessionSet = false;
>>>> 
>>>>  +    //private final KeyFactory keyFactory;
>>>>       private SessionViewStorageFactory sessionViewStorageFactory;
>>>> 
>>>>       public ServerSideStateCacheImpl()
>>>>       {
>>>>           FacesContext facesContext = 
> FacesContext.getCurrentInstance();
>>>>           String randomMode =
>>>> 
> WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
>>>>  -                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>  +                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>                   
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
>>>>           if
>>>> 
> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
>>>>           {
>>>>  -            sessionViewStorageFactory = new 
> SessionViewStorageFactory(
>>>>  +            //keyFactory = new 
> SecureRandomKeyFactory(facesContext);
>>>>  +            sessionViewStorageFactory = new 
> RandomSessionViewStorageFactory(
>>>>                       new SecureRandomKeyFactory(facesContext));
>>>>           }
>>>>           else if
>>>>  (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
>>>>           {
>>>>  -            sessionViewStorageFactory = new 
> SessionViewStorageFactory(
>>>>  +            //keyFactory = new RandomKeyFactory(facesContext);
>>>>  +            sessionViewStorageFactory = new 
> RandomSessionViewStorageFactory(
>>>>                       new RandomKeyFactory(facesContext));
>>>>           }
>>>>           else
>>>>           {
>>>>  -            sessionViewStorageFactory = new 
> SessionViewStorageFactory(new
>>>>  CounterKeyFactory());
>>>>  +            //keyFactory = new CounterKeyFactory();
>>>>  +            sessionViewStorageFactory = new
>>>>  CounterSessionViewStorageFactory(new CounterKeyFactory());
>>>>           }
>>>>       }
>>>>  -
>>>>  +
>>>>       //------------------------------------- METHODS COPIED FROM
>>>>  JspStateManagerImpl--------------------------------
>>>> 
>>>>       protected Object getServerStateId(FacesContext facesContext, 
> Object state)
>>>>  @@ -285,16 +296,16 @@ class ServerSideStateCacheImpl extends S
>>>>           }
>>>> 
>>>>           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()) 
> &&
>>>>  +                if
>>>>  (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) 
> &&
>>>> 
>>>>  Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
>>>> 
>>>>  .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
>>>>                   {
>>>>  @@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends S
>>>>                   }
>>>>               }
>>>>           }
>>>>  -
>>>>  +
>>>>           SerializedViewKey nextKey =
>>>>  getSessionViewStorageFactory().createSerializedViewKey(
>>>>                   context, context.getViewRoot().getViewId(),
>>>>  getNextViewSequence(context));
>>>>           viewCollection.add(context, serializeView(context, 
> serializedView),
>>>>  nextKey, key);
>>>>  @@ -339,14 +350,14 @@ class ServerSideStateCacheImpl extends S
>>>>                   }
>>>>               }
>>>>               
> attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR,
>>>>  serializedView);
>>>>  -
>>>>  +
>>>>               if 
> (getNumberOfSequentialViewsInSession(externalContext) != null
>>>>  &&
>>>>                   
> getNumberOfSequentialViewsInSession(externalContext) > 0)
>>>>               {
>>>>                   SerializedViewKey key = 
> getSessionViewStorageFactory().
>>>>                           createSerializedViewKey(context, viewId, 
> sequence);
>>>>                   attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR, 
> key);
>>>>  -
>>>>  +
>>>>                   if 
> (isUseFlashScopePurgeViewsInSession(externalContext))
>>>>                   {
>>>> 
>>>>  externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, 
> key);
>>>>  @@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends S
>>>>                   //Object[] stateArray = (Object[]) serializedView;
>>>> 
>>>>                   ObjectOutputStream out = new 
> ObjectOutputStream(os);
>>>>  -
>>>>  +
>>>>                   out.writeObject(serializedView);
>>>>                   //out.writeObject(stateArray[0]);
>>>>                   //out.writeObject(stateArray[1]);
>>>>  @@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends S
>>>>                       final ObjectInputStream in = new
>>>>  MyFacesObjectInputStream(is);
>>>>                       ois = in;
>>>>                       Object object = null;
>>>>  -                    if (System.getSecurityManager() != null)
>>>>  +                    if (System.getSecurityManager() != null)
>>>>                       {
>>>>  -                        object = AccessController.doPrivileged(new
>>>>  PrivilegedExceptionAction<Object>()
>>>>  +                        object = AccessController.doPrivileged(new
>>>>  PrivilegedExceptionAction<Object>()
>>>>                           {
>>>>                               public Object run() throws
>>>>  PrivilegedActionException, IOException, ClassNotFoundException
>>>>                               {
>>>>  @@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends S
>>>>                       }
>>>>                   }
>>>>               }
>>>>  -            catch (PrivilegedActionException e)
>>>>  +            catch (PrivilegedActionException e)
>>>>               {
>>>>                   log.log(Level.SEVERE, "Exiting 
> deserializeView - Could not
>>>>  deserialize state: " + e.getMessage(), e);
>>>>                   return null;
>>>>  @@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends S
>>>>               return null;
>>>>           }
>>>>       }
>>>>  -
>>>>  +
>>>>       protected static class SerializedViewCollection implements 
> Serializable
>>>>       {
>>>>           private static final long serialVersionUID = 
> -3734849062185115847L;
>>>>  @@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends S
>>>>           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 =
>>>>  +
>>>>  +        private final Map<SerializedViewKey, 
> SerializedViewKey>
>>>>  _precedence =
>>>>               new HashMap<SerializedViewKey, 
> SerializedViewKey>();
>>>> 
>>>>           // old views will be hold as soft references which will be 
> removed by
>>>>  @@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends S
>>>>                   // into the map.
>>>>                   state = null;
>>>>               }
>>>>  -
>>>>  +
>>>>               Integer maxCount = 
> getNumberOfSequentialViewsInSession(context);
>>>>               if (maxCount != null)
>>>>               {
>>>>  @@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends S
>>>>                     previousKey = _precedence.get(previousKey);
>>>>                     count++;
>>>>                   } while (previousKey != null && count < 
> maxCount);
>>>>  -
>>>>  +
>>>>                   if (previousKey != null)
>>>>                   {
>>>>                       SerializedViewKey keyToRemove = 
> (SerializedViewKey)
>>>>  previousKey;
>>>>  @@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends S
>>>>                           {
>>>>                               _serializedViews.remove(keyToRemove);
>>>>                           }
>>>>  -
>>>>  +
>>>>                           keyToRemove = 
> _precedence.remove(keyToRemove);
>>>>                       }  while(keyToRemove != null);
>>>>                   }
>>>>  @@ -680,11 +691,11 @@ class ServerSideStateCacheImpl extends S
>>>>               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,
>>>>  +                    // 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
>>>>  @@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends S
>>>>                   if (_serializedViews.containsKey(key) &&
>>>> 
>>>> 
> !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
>>>>                   {
>>>>  -
>>>>  +
>>>>                       getOldSerializedViewsMap().put(key,
>>>>  _serializedViews.remove(key));
>>>>                   }
>>>>                   else
>>>>  @@ -708,10 +719,10 @@ class ServerSideStateCacheImpl extends S
>>>> 
>>>>           protected Integer 
> getNumberOfSequentialViewsInSession(FacesContext
>>>>  context)
>>>>           {
>>>>  -            return
>>>> 
> WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
>>>>  +            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
>>>>  @@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends S
>>>>               FacesContext context = 
> FacesContext.getCurrentInstance();
>>>>               if (_oldSerializedViews == null && context != 
> null)
>>>>               {
>>>>  -                String cacheMode = 
> getCacheOldViewsInSessionMode(context);
>>>>  +                String cacheMode = 
> getCacheOldViewsInSessionMode(context);
>>>>                   if 
> (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
>>>>                   {
>>>>                       _oldSerializedViews = new
>>>>  ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, 
> true);
>>>>  @@ -773,13 +784,13 @@ class ServerSideStateCacheImpl extends S
>>>>                       _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
>>>>  @@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends S
>>>>               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;
>>>>  @@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends S
>>>>                   return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
>>>>               }
>>>>           }
>>>>  -
>>>>  +
>>>>           public Object get(SerializedViewKey key)
>>>>           {
>>>>               Object value = _serializedViews.get(key);
>>>>  @@ -846,7 +857,172 @@ class ServerSideStateCacheImpl extends S
>>>>           }
>>>>       }
>>>> 
>>>>  +    /**
>>>>  +     * Base implementation where all keys used to identify the 
> state of a view
>>>>  should
>>>>  +     * extend.
>>>>  +     */
>>>>  +    protected abstract static class SerializedViewKey implements 
> Serializable
>>>>  +    {
>>>>  +    }
>>>>  +
>>>>  +    /**
>>>>  +     * Implementation of SerializedViewKey, where the hashCode of 
> the viewId is
>>>>  used
>>>>  +     * and the sequenceId is a numeric value.
>>>>  +     */
>>>>  +    private static class IntIntSerializedViewKey extends 
> SerializedViewKey
>>>>  +        implements Serializable
>>>>  +    {
>>>>  +        private static final long serialVersionUID = 
> -1170697124386063642L;
>>>>  +
>>>>  +        private final int _viewId;
>>>>  +        private final int _sequenceId;
>>>>  +
>>>>  +        public IntIntSerializedViewKey(int viewId, int sequence)
>>>>  +        {
>>>>  +            _sequenceId = sequence;
>>>>  +            _viewId = viewId;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public boolean equals(Object obj)
>>>>  +        {
>>>>  +            if (obj == null)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (getClass() != obj.getClass())
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            final IntIntSerializedViewKey other = 
> (IntIntSerializedViewKey)
>>>>  obj;
>>>>  +            if (this._viewId != other._viewId)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (this._sequenceId != other._sequenceId)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            return true;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public int hashCode()
>>>>  +        {
>>>>  +            int hash = 7;
>>>>  +            hash = 83 * hash + this._viewId;
>>>>  +            hash = 83 * hash + this._sequenceId;
>>>>  +            return hash;
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +    /**
>>>>  +     * Implementation of SerializedViewKey, where the hashCode of 
> the viewId is
>>>>  used
>>>>  +     * and the sequenceId is a string value.
>>>>  +     */
>>>>  +    private static class IntByteArraySerializedViewKey extends
>>>>  SerializedViewKey
>>>>  +        implements Serializable
>>>>  +    {
>>>>  +        private final int _viewId;
>>>>  +        private final byte[] _sequenceId;
>>>>  +
>>>>  +        public IntByteArraySerializedViewKey(int viewId, byte[] 
> sequence)
>>>>  +        {
>>>>  +            _sequenceId = sequence;
>>>>  +            _viewId = viewId;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public boolean equals(Object obj)
>>>>  +        {
>>>>  +            if (obj == null)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (getClass() != obj.getClass())
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            final IntByteArraySerializedViewKey other =
>>>>  (IntByteArraySerializedViewKey) obj;
>>>>  +            if (this._viewId != other._viewId)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (!Arrays.equals(this._sequenceId, 
> other._sequenceId))
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            return true;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public int hashCode()
>>>>  +        {
>>>>  +            int hash = 5;
>>>>  +            hash = 37 * hash + this._viewId;
>>>>  +            hash = 37 * hash + Arrays.hashCode(this._sequenceId);
>>>>  +            return hash;
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +
>>>>  +    /**
>>>>  +     * Implementation of SerializedViewKey, where the viewId and 
> the sequenceId
>>>>  can be
>>>>  +     * anything.
>>>>  +     */
>>>>  +    private static class ReferenceSerializedViewKey<I,K> 
> extends
>>>>  SerializedViewKey
>>>>  +        implements Serializable
>>>>  +    {
>>>>  +        private static final long serialVersionUID = 
> -1170697124386063642L;
>>>>  +
>>>>  +        private final I _viewId;
>>>>  +        private final K _sequenceId;
>>>> 
>>>>  +        public ReferenceSerializedViewKey()
>>>>  +        {
>>>>  +            _sequenceId = null;
>>>>  +            _viewId = null;
>>>>  +        }
>>>>  +        public ReferenceSerializedViewKey(I viewId, K sequence)
>>>>  +        {
>>>>  +            _sequenceId = sequence;
>>>>  +            _viewId = viewId;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public boolean equals(Object obj)
>>>>  +        {
>>>>  +            if (obj == null)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (getClass() != obj.getClass())
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            final ReferenceSerializedViewKey<I, K> other =
>>>>  (ReferenceSerializedViewKey<I, K>) obj;
>>>>  +            if (this._viewId != other._viewId && 
> (this._viewId == null
>>>>  || !this._viewId.equals(other._viewId)))
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (this._sequenceId != other._sequenceId &&
>>>>  +                (this._sequenceId == null ||
>>>>  !this._sequenceId.equals(other._sequenceId)))
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            return true;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public int hashCode()
>>>>  +        {
>>>>  +            int hash = 7;
>>>>  +            hash = 83 * hash + (this._viewId != null ? 
> this._viewId.hashCode()
>>>>  : 0);
>>>>  +            hash = 83 * hash + (this._sequenceId != null ?
>>>>  this._sequenceId.hashCode() : 0);
>>>>  +            return hash;
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>       //------------------------------------- METHOD FROM StateCache
>>>>  ------------------------------------------------
>>>> 
>>>>       @Override
>>>>  @@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl extends S
>>>>           }
>>>>           //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);
>>>>       }
>>>> 
>>>>  @@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl extends S
>>>>       {
>>>>           return
>>>> 
> getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
>>>>       }
>>>>  -
>>>>  +
>>>>       @Override
>>>>       public boolean 
> isWriteStateAfterRenderViewRequired(FacesContext
>>>>  facesContext)
>>>>       {
>>>>  @@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl extends S
>>>>       }
>>>> 
>>>>       //------------------------------------- Custom methods
>>>>  -----------------------------------------------------
>>>>  -
>>>>  +
>>>>       private boolean 
> isUseFlashScopePurgeViewsInSession(ExternalContext
>>>>  externalContext)
>>>>       {
>>>>           if (_useFlashScopePurgeViewsInSession == null)
>>>>  @@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl extends S
>>>>           }
>>>>           return _useFlashScopePurgeViewsInSession;
>>>>       }
>>>>  -
>>>>  +
>>>>       private Integer 
> getNumberOfSequentialViewsInSession(ExternalContext
>>>>  externalContext)
>>>>       {
>>>>           if (!_numberOfSequentialViewsInSessionSet)
>>>>           {
>>>>               _numberOfSequentialViewsInSession =
>>>>  WebConfigParamUtils.getIntegerInitParameter(
>>>>  -                    externalContext,
>>>>  +                    externalContext,
>>>>                       NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
>>>>               _numberOfSequentialViewsInSessionSet = true;
>>>>           }
>>>>           return _numberOfSequentialViewsInSession;
>>>>       }
>>>>  -
>>>>  +
>>>>       protected KeyFactory getKeyFactory(FacesContext facesContext)
>>>>       {
>>>>           //return keyFactory;
>>>>           return sessionViewStorageFactory.getKeyFactory();
>>>>       }
>>>>  -
>>>>  +
>>>>       protected SessionViewStorageFactory 
> getSessionViewStorageFactory()
>>>>       {
>>>>           return sessionViewStorageFactory;
>>>>       }
>>>>  +
>>>> 
>>>>  +    protected abstract static class KeyFactory<K, V>
>>>>  +    {
>>>>  +
>>>>  +        /**
>>>>  +         * Generates a unique key per session
>>>>  +         *
>>>>  +         * @param facesContext
>>>>  +         * @return
>>>>  +         */
>>>>  +        public abstract K generateKey(FacesContext facesContext);
>>>>  +
>>>>  +        /**
>>>>  +         * Encode a Key into a value that will be used as view 
> state session
>>>>  token
>>>>  +         *
>>>>  +         * @param key
>>>>  +         * @return
>>>>  +         */
>>>>  +        public abstract V encode(K key);
>>>> 
>>>>  +        /**
>>>>  +         * Decode a view state session token into a key
>>>>  +         *
>>>>  +         * @param value
>>>>  +         * @return
>>>>  +         */
>>>>  +        public abstract K decode(V value);
>>>>  +
>>>>  +    }
>>>>  +
>>>>  +    private static class CounterKeyFactory extends 
> KeyFactory<Integer,
>>>>  String>
>>>>  +    {
>>>>  +        /**
>>>>  +         * Take the counter from session scope and increment
>>>>  +         *
>>>>  +         * @param facesContext
>>>>  +         * @return
>>>>  +         */
>>>>  +        @Override
>>>>  +        public Integer generateKey(FacesContext facesContext)
>>>>  +        {
>>>>  +            ExternalContext externalContext =
>>>>  facesContext.getExternalContext();
>>>>  +            Object sessionObj = externalContext.getSession(true);
>>>>  +            Integer sequence = null;
>>>>  +            synchronized(sessionObj) // synchronized to increase 
> sequence if
>>>>  multiple requests
>>>>  +                                    // are handled at the same 
> time for the
>>>>  session
>>>>  +            {
>>>>  +                Map<String, Object> map =
>>>>  externalContext.getSessionMap();
>>>>  +                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);
>>>>  +            }
>>>>  +            return sequence;
>>>>  +        }
>>>>  +
>>>>  +        public String encode(Integer sequence)
>>>>  +        {
>>>>  +            return Integer.toString(sequence, 
> Character.MAX_RADIX);
>>>>  +        }
>>>>  +
>>>>  +        public Integer decode(String serverStateId)
>>>>  +        {
>>>>  +             return Integer.valueOf((String) serverStateId,
>>>>  Character.MAX_RADIX);
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +    /**
>>>>  +     * This factory generate a key composed by a counter and a 
> random number.
>>>>  The
>>>>  +     * counter ensures uniqueness, and the random number prevents 
> guess the
>>>>  next
>>>>  +     * session token.
>>>>  +     */
>>>>  +    private static class SecureRandomKeyFactory extends 
> KeyFactory<byte[],
>>>>  String>
>>>>  +    {
>>>>  +        private final SessionIdGenerator sessionIdGenerator;
>>>>  +        private final int length;
>>>>  +
>>>>  +        public SecureRandomKeyFactory(FacesContext facesContext)
>>>>  +        {
>>>>  +            length =
>>>> 
> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>  +                    
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>  +
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>  +            sessionIdGenerator = new SessionIdGenerator();
>>>>  +            sessionIdGenerator.setSessionIdLength(length);
>>>>  +            String secureRandomClass =
>>>>  WebConfigParamUtils.getStringInitParameter(
>>>>  +                    facesContext.getExternalContext(),
>>>>  +
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
>>>>  +            if (secureRandomClass != null)
>>>>  +            {
>>>>  +                
> sessionIdGenerator.setSecureRandomClass(secureRandomClass);
>>>>  +            }
>>>>  +            String secureRandomProvider =
>>>>  WebConfigParamUtils.getStringInitParameter(
>>>>  +                    facesContext.getExternalContext(),
>>>>  +
>>>> 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
>>>>  +            if (secureRandomProvider != null)
>>>>  +            {
>>>>  +
>>>>  sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
>>>>  +            }
>>>>  +            String secureRandomAlgorithm =
>>>>  WebConfigParamUtils.getStringInitParameter(
>>>>  +                    facesContext.getExternalContext(),
>>>>  +
>>>> 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
>>>>  +            if (secureRandomAlgorithm != null)
>>>>  +            {
>>>>  +
>>>>  sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
>>>>  +            }
>>>>  +        }
>>>>  +
>>>>  +        public Integer generateCounterKey(FacesContext 
> facesContext)
>>>>  +        {
>>>>  +            ExternalContext externalContext =
>>>>  facesContext.getExternalContext();
>>>>  +            Object sessionObj = externalContext.getSession(true);
>>>>  +            Integer sequence = null;
>>>>  +            synchronized(sessionObj) // synchronized to increase 
> sequence if
>>>>  multiple requests
>>>>  +                                    // are handled at the same 
> time for the
>>>>  session
>>>>  +            {
>>>>  +                Map<String, Object> map =
>>>>  externalContext.getSessionMap();
>>>>  +                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);
>>>>  +            }
>>>>  +            return sequence;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public byte[] generateKey(FacesContext facesContext)
>>>>  +        {
>>>>  +            byte[] array = new byte[length];
>>>>  +            byte[] key = new byte[length+4];
>>>>  +
>>>>  +            sessionIdGenerator.getRandomBytes(array);
>>>>  +            for (int i = 0; i < array.length; i++)
>>>>  +            {
>>>>  +                key[i] = array[i];
>>>>  +            }
>>>>  +            int value = generateCounterKey(facesContext);
>>>>  +            key[array.length] =  (byte) (value >>> 24);
>>>>  +            key[array.length+1] =  (byte) (value >>> 16);
>>>>  +            key[array.length+2] =  (byte) (value >>> 8);
>>>>  +            key[array.length+3] =  (byte) (value);
>>>>  +
>>>>  +            return key;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public String encode(byte[] key)
>>>>  +        {
>>>>  +            return new String(Hex.encodeHex(key));
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public byte[] decode(String value)
>>>>  +        {
>>>>  +            try
>>>>  +            {
>>>>  +                return Hex.decodeHex(value.toCharArray());
>>>>  +            }
>>>>  +            catch (DecoderException ex)
>>>>  +            {
>>>>  +                // Cannot decode, ignore silently, later it will 
> be handled as
>>>>  +                // ViewExpiredException
>>>>  +            }
>>>>  +            return null;
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +    private static class RandomKeyFactory extends 
> KeyFactory<byte[],
>>>>  String>
>>>>  +    {
>>>>  +        private final Random random;
>>>>  +        private final int length;
>>>>  +
>>>>  +        public RandomKeyFactory(FacesContext facesContext)
>>>>  +        {
>>>>  +            length =
>>>> 
> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>  +                    
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>  +
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>  +            random = new 
> Random(((int)System.nanoTime())+this.hashCode());
>>>>  +        }
>>>>  +
>>>>  +        public Integer generateCounterKey(FacesContext 
> facesContext)
>>>>  +        {
>>>>  +            ExternalContext externalContext =
>>>>  facesContext.getExternalContext();
>>>>  +            Object sessionObj = externalContext.getSession(true);
>>>>  +            Integer sequence = null;
>>>>  +            synchronized(sessionObj) // synchronized to increase 
> sequence if
>>>>  multiple requests
>>>>  +                                    // are handled at the same 
> time for the
>>>>  session
>>>>  +            {
>>>>  +                Map<String, Object> map =
>>>>  externalContext.getSessionMap();
>>>>  +                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);
>>>>  +            }
>>>>  +            return sequence;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public byte[] generateKey(FacesContext facesContext)
>>>>  +        {
>>>>  +            byte[] array = new byte[length];
>>>>  +            byte[] key = new byte[length+4];
>>>>  +
>>>>  +            //sessionIdGenerator.getRandomBytes(array);
>>>>  +            random.nextBytes(array);
>>>>  +            for (int i = 0; i < array.length; i++)
>>>>  +            {
>>>>  +                key[i] = array[i];
>>>>  +            }
>>>>  +            int value = generateCounterKey(facesContext);
>>>>  +            key[array.length] =  (byte) (value >>> 24);
>>>>  +            key[array.length+1] =  (byte) (value >>> 16);
>>>>  +            key[array.length+2] =  (byte) (value >>> 8);
>>>>  +            key[array.length+3] =  (byte) (value);
>>>>  +
>>>>  +            return key;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public String encode(byte[] key)
>>>>  +        {
>>>>  +            return new String(Hex.encodeHex(key));
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public byte[] decode(String value)
>>>>  +        {
>>>>  +            try
>>>>  +            {
>>>>  +                return Hex.decodeHex(value.toCharArray());
>>>>  +            }
>>>>  +            catch (DecoderException ex)
>>>>  +            {
>>>>  +                // Cannot decode, ignore silently, later it will 
> be handled as
>>>>  +                // ViewExpiredException
>>>>  +            }
>>>>  +            return null;
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +    /**
>>>>  +     *
>>>>  +     * @param <T>
>>>>  +     * @param <K>
>>>>  +     * @param <V>
>>>>  +     */
>>>>  +    protected abstract static class SessionViewStorageFactory 
> <T extends
>>>>  KeyFactory<K,V>, K, V >
>>>>  +    {
>>>>  +        private KeyFactory<K, V> keyFactory;
>>>>  +
>>>>  +        public SessionViewStorageFactory(KeyFactory<K, V> 
> keyFactory)
>>>>  +        {
>>>>  +            this.keyFactory = keyFactory;
>>>>  +        }
>>>>  +
>>>>  +        public KeyFactory<K, V> getKeyFactory()
>>>>  +        {
>>>>  +            return keyFactory;
>>>>  +        }
>>>>  +
>>>>  +        public abstract SerializedViewCollection
>>>>  createSerializedViewCollection(
>>>>  +                FacesContext context);
>>>>  +
>>>>  +        public abstract SerializedViewKey createSerializedViewKey(
>>>>  +                FacesContext facesContext, String viewId, K key);
>>>>  +
>>>>  +    }
>>>>  +
>>>>  +    private static class CounterSessionViewStorageFactory
>>>>  +        extends SessionViewStorageFactory <KeyFactory
>>>>  <Integer,String>, Integer, String>
>>>>  +    {
>>>>  +        public 
> CounterSessionViewStorageFactory(KeyFactory<Integer,
>>>>  String> keyFactory)
>>>>  +        {
>>>>  +            super(keyFactory);
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public SerializedViewCollection 
> createSerializedViewCollection(
>>>>  +                FacesContext context)
>>>>  +        {
>>>>  +            return new SerializedViewCollection();
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public SerializedViewKey createSerializedViewKey(
>>>>  +                FacesContext context, String viewId, Integer key)
>>>>  +        {
>>>>  +            if (context.isProjectStage(ProjectStage.Production))
>>>>  +            {
>>>>  +                return new 
> IntIntSerializedViewKey(viewId.hashCode(), key);
>>>>  +            }
>>>>  +            else
>>>>  +            {
>>>>  +                return new ReferenceSerializedViewKey(viewId, 
> key);
>>>>  +            }
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +    private static class RandomSessionViewStorageFactory
>>>>  +        extends SessionViewStorageFactory <KeyFactory 
> <byte[],String>,
>>>>  byte[], String>
>>>>  +    {
>>>>  +        public 
> RandomSessionViewStorageFactory(KeyFactory<byte[], String>
>>>>  keyFactory)
>>>>  +        {
>>>>  +            super(keyFactory);
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public SerializedViewCollection 
> createSerializedViewCollection(
>>>>  +                FacesContext context)
>>>>  +        {
>>>>  +            return new SerializedViewCollection();
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public SerializedViewKey createSerializedViewKey(
>>>>  +                FacesContext context, String viewId, byte[] key)
>>>>  +        {
>>>>  +            if (context.isProjectStage(ProjectStage.Production))
>>>>  +            {
>>>>  +                return new 
> IntByteArraySerializedViewKey(viewId.hashCode(),
>>>>  key);
>>>>  +            }
>>>>  +            else
>>>>  +            {
>>>>  +                return new ReferenceSerializedViewKey(viewId, 
> key);
>>>>  +            }
>>>>  +        }
>>>>  +    }
>>>>  }
>>>> 
> 

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Leonardo Uribe <lu...@gmail.com>.
2012/11/14 Leonardo Uribe <lu...@gmail.com>:
> Hi
>
> 2012/11/14 Mark Struberg <st...@yahoo.de>:
>> Leo, there was a reason I removed it.
>>
>>
>> Even after discussing this over 10 mails in a private thread you don't get it it seems. I will open a VOTE about principal design fundamentals and we will act according to this.
>>
>> Just you be prepated: A HASH IS NOT UNIQUE!
>>
>
> But I have told you multiple times, the algorithm does not rely on the
> hash to be unique, relies on the counter.
>
>> Also saying in the mails you understand and then doing the same crazy code again is just plain ******
>>
>> I gonna revert it now and will write up the VOTE
>
> The best way to resolve this is putting the arguments on the table and
> vote over that, right? after the vote we can do the necessary changes
> over the code. I have committed the fix that I suppose is correct.
>

It is more, could you please try if the fix proposed by me works in your case?
could you please show two viewIds that can be written as valid file names that
has the same hashCode? I'm open to change my mind, but first I need
concrete arguments to do that.

> regards,
>
> Leonardo
>
>>
>> LieGrue,
>> strub
>>
>>
>>
>>
>> ----- Original Message -----
>>> From: "lu4242@apache.org" <lu...@apache.org>
>>> To: commits@myfaces.apache.org
>>> Cc:
>>> Sent: Wednesday, November 14, 2012 10:23 PM
>>> Subject: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/
>>>
>>> Author: lu4242
>>> Date: Wed Nov 14 21:23:35 2012
>>> New Revision: 1409414
>>>
>>> URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
>>> Log:
>>> MYFACES-3638 revert commit 1408993 to include later solution without
>>> refactoring.
>>>
>>> Added:
>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>       - copied unchanged from r1408992,
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>> Removed:
>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
>>> Modified:
>>>     myfaces/core/trunk/impl/   (props changed)
>>>
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>
>>> Propchange: myfaces/core/trunk/impl/
>>> ------------------------------------------------------------------------------
>>> --- svn:ignore (original)
>>> +++ svn:ignore Wed Nov 14 21:23:35 2012
>>> @@ -7,7 +7,8 @@ target
>>> *.iml
>>> *.ipr
>>> *.iws
>>> -.idea
>>> .settings
>>> +
>>> cobertura.ser
>>> +
>>> test-output
>>>
>>> Modified:
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>> URL:
>>> http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
>>> ==============================================================================
>>> ---
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>> (original)
>>> +++
>>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>> Wed Nov 14 21:23:35 2012
>>> @@ -30,16 +30,21 @@ import java.security.AccessController;
>>> import java.security.PrivilegedActionException;
>>> import java.security.PrivilegedExceptionAction;
>>> import java.util.ArrayList;
>>> +import java.util.Arrays;
>>> import java.util.HashMap;
>>> import java.util.List;
>>> import java.util.Map;
>>> +import java.util.Random;
>>> import java.util.logging.Level;
>>> import java.util.logging.Logger;
>>> import java.util.zip.GZIPInputStream;
>>> import java.util.zip.GZIPOutputStream;
>>> +import javax.faces.application.ProjectStage;
>>>
>>> import javax.faces.context.ExternalContext;
>>> import javax.faces.context.FacesContext;
>>> +import org.apache.commons.codec.DecoderException;
>>> +import org.apache.commons.codec.binary.Hex;
>>>
>>> import org.apache.commons.collections.map.AbstractReferenceMap;
>>> import org.apache.commons.collections.map.ReferenceMap;
>>> @@ -52,22 +57,22 @@ import org.apache.myfaces.shared.util.We
>>> class ServerSideStateCacheImpl extends StateCache<Object, Object>
>>> {
>>>      private static final Logger log =
>>> Logger.getLogger(ServerSideStateCacheImpl.class.getName());
>>> -
>>> -    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>> +
>>> +    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>>          ServerSideStateCacheImpl.class.getName() +
>>> ".SERIALIZED_VIEW";
>>> -
>>> -    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>> +
>>> +    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>>          ServerSideStateCacheImpl.class.getName() +
>>> ".RESTORED_SERIALIZED_VIEW";
>>>
>>> -    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>> +    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>          ServerSideStateCacheImpl.class.getName() +
>>> ".RESTORED_VIEW_KEY";
>>> -
>>> +
>>>      /**
>>>       * Defines the amount (default = 20) of the latest views are stored in
>>> session.
>>> -     *
>>> +     *
>>>       * <p>Only applicable if state saving method is "server" (=
>>> default).
>>>       * </p>
>>> -     *
>>> +     *
>>>       */
>>>      @JSFWebConfigParam(defaultValue="20",since="1.1",
>>> classType="java.lang.Integer", group="state",
>>> tags="performance")
>>>      private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM =
>>> "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
>>> @@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
>>>      /**
>>>       * 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>Only applicable if state saving method is "server" (=
>>> default). For example, if this param has value = 2 and
>>> +     *
>>> +     * <p>Only applicable if state saving method is "server" (=
>>> default). 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
>>> @@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends S
>>>      @JSFWebConfigParam(since="2.0.6",
>>> classType="java.lang.Integer", group="state",
>>> tags="performance")
>>>      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;
>>>
>>>      /**
>>> -     * Indicate if the state should be serialized before save it on the
>>> session.
>>> +     * Indicate if the state should be serialized before save it on the
>>> session.
>>>       * <p>
>>>       * 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.
>>> @@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends S
>>>
>>>      /**
>>>       * Indicates that the serialized state will be compressed before it is
>>> written to the session. By default true.
>>> -     *
>>> +     *
>>>       * 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.
>>> @@ -140,38 +145,38 @@ class ServerSideStateCacheImpl extends S
>>>       * <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>
>>> +     * <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", group="state",
>>> tags="performance")
>>>      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
>>> +     * 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";
>>>
>>>      /**
>>>       * 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.
>>> -     *
>>> +     *
>>>       * <p>
>>>       * Only applicable if state saving method is "server" (=
>>> default).
>>>       * The default value is false.</p>
>>> @@ -183,84 +188,90 @@ class ServerSideStateCacheImpl extends S
>>>      private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE =
>>> "none";
>>>      private static final String
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM = "secureRandom";
>>>      private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM =
>>> "random";
>>> -
>>> +
>>>      /**
>>>       * Adds a random key to the generated view state session token.
>>>       */
>>> -    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>> expectedValues="secureRandom, random, none",
>>> +    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>> expectedValues="secureRandom, random, none",
>>>              defaultValue="none", group="state")
>>>      private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
>>>              =
>>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
>>> -    private static final String
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>> +    private static final String
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>              RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
>>>
>>>      /**
>>>       * Set the default length of the random key added to the view state session
>>> token.
>>> -     * By default is 8.
>>> +     * By default is 8.
>>>       */
>>>      @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>> defaultValue="8", group="state")
>>> -    static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>> +    private static final String
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>              =
>>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
>>> -    static final int
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>> +    private static final int
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>
>>>      /**
>>> -     * Sets the random class to initialize the secure random id generator.
>>> +     * Sets the random class to initialize the secure random id generator.
>>>       * By default it uses java.security.SecureRandom
>>>       */
>>>      @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>> group="state")
>>> -    static final String
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>> +    private static final String
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>              =
>>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
>>> -
>>> +
>>>      /**
>>>       * Sets the random provider to initialize the secure random id generator.
>>>       */
>>>      @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>> group="state")
>>> -    static final String
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>> +    private static final String
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>              =
>>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
>>> -
>>> +
>>>      /**
>>> -     * Sets the random algorithm to initialize the secure random id generator.
>>> +     * Sets the random algorithm to initialize the secure random id generator.
>>>       * By default is SHA1PRNG
>>>       */
>>>      @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>> defaultValue="SHA1PRNG", group="state")
>>> -    static final String
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>> +    private static final String
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>              =
>>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
>>> -
>>> -
>>> +
>>> +
>>>      private static final int UNCOMPRESSED_FLAG = 0;
>>>      private static final int COMPRESSED_FLAG = 1;
>>> -
>>> +
>>>      private static final Object[] EMPTY_STATES = new Object[]{null, null};
>>>
>>> +    //private static final int JSF_SEQUENCE_INDEX = 0;
>>> +
>>>      private Boolean _useFlashScopePurgeViewsInSession = null;
>>> -
>>> +
>>>      private Integer _numberOfSequentialViewsInSession = null;
>>>      private boolean _numberOfSequentialViewsInSessionSet = false;
>>>
>>> +    //private final KeyFactory keyFactory;
>>>      private SessionViewStorageFactory sessionViewStorageFactory;
>>>
>>>      public ServerSideStateCacheImpl()
>>>      {
>>>          FacesContext facesContext = FacesContext.getCurrentInstance();
>>>          String randomMode =
>>> WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
>>> -                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>> +                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>                  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
>>>          if
>>> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
>>>          {
>>> -            sessionViewStorageFactory = new SessionViewStorageFactory(
>>> +            //keyFactory = new SecureRandomKeyFactory(facesContext);
>>> +            sessionViewStorageFactory = new RandomSessionViewStorageFactory(
>>>                      new SecureRandomKeyFactory(facesContext));
>>>          }
>>>          else if
>>> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
>>>          {
>>> -            sessionViewStorageFactory = new SessionViewStorageFactory(
>>> +            //keyFactory = new RandomKeyFactory(facesContext);
>>> +            sessionViewStorageFactory = new RandomSessionViewStorageFactory(
>>>                      new RandomKeyFactory(facesContext));
>>>          }
>>>          else
>>>          {
>>> -            sessionViewStorageFactory = new SessionViewStorageFactory(new
>>> CounterKeyFactory());
>>> +            //keyFactory = new CounterKeyFactory();
>>> +            sessionViewStorageFactory = new
>>> CounterSessionViewStorageFactory(new CounterKeyFactory());
>>>          }
>>>      }
>>> -
>>> +
>>>      //------------------------------------- METHODS COPIED FROM
>>> JspStateManagerImpl--------------------------------
>>>
>>>      protected Object getServerStateId(FacesContext facesContext, Object state)
>>> @@ -285,16 +296,16 @@ class ServerSideStateCacheImpl extends S
>>>          }
>>>
>>>          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()) &&
>>> +                if
>>> (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) &&
>>>
>>> Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
>>>
>>> .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
>>>                  {
>>> @@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends S
>>>                  }
>>>              }
>>>          }
>>> -
>>> +
>>>          SerializedViewKey nextKey =
>>> getSessionViewStorageFactory().createSerializedViewKey(
>>>                  context, context.getViewRoot().getViewId(),
>>> getNextViewSequence(context));
>>>          viewCollection.add(context, serializeView(context, serializedView),
>>> nextKey, key);
>>> @@ -339,14 +350,14 @@ class ServerSideStateCacheImpl extends S
>>>                  }
>>>              }
>>>              attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR,
>>> serializedView);
>>> -
>>> +
>>>              if (getNumberOfSequentialViewsInSession(externalContext) != null
>>> &&
>>>                  getNumberOfSequentialViewsInSession(externalContext) > 0)
>>>              {
>>>                  SerializedViewKey key = getSessionViewStorageFactory().
>>>                          createSerializedViewKey(context, viewId, sequence);
>>>                  attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
>>> -
>>> +
>>>                  if (isUseFlashScopePurgeViewsInSession(externalContext))
>>>                  {
>>>
>>> externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
>>> @@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends S
>>>                  //Object[] stateArray = (Object[]) serializedView;
>>>
>>>                  ObjectOutputStream out = new ObjectOutputStream(os);
>>> -
>>> +
>>>                  out.writeObject(serializedView);
>>>                  //out.writeObject(stateArray[0]);
>>>                  //out.writeObject(stateArray[1]);
>>> @@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends S
>>>                      final ObjectInputStream in = new
>>> MyFacesObjectInputStream(is);
>>>                      ois = in;
>>>                      Object object = null;
>>> -                    if (System.getSecurityManager() != null)
>>> +                    if (System.getSecurityManager() != null)
>>>                      {
>>> -                        object = AccessController.doPrivileged(new
>>> PrivilegedExceptionAction<Object>()
>>> +                        object = AccessController.doPrivileged(new
>>> PrivilegedExceptionAction<Object>()
>>>                          {
>>>                              public Object run() throws
>>> PrivilegedActionException, IOException, ClassNotFoundException
>>>                              {
>>> @@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends S
>>>                      }
>>>                  }
>>>              }
>>> -            catch (PrivilegedActionException e)
>>> +            catch (PrivilegedActionException e)
>>>              {
>>>                  log.log(Level.SEVERE, "Exiting deserializeView - Could not
>>> deserialize state: " + e.getMessage(), e);
>>>                  return null;
>>> @@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends S
>>>              return null;
>>>          }
>>>      }
>>> -
>>> +
>>>      protected static class SerializedViewCollection implements Serializable
>>>      {
>>>          private static final long serialVersionUID = -3734849062185115847L;
>>> @@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends S
>>>          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 =
>>> +
>>> +        private final Map<SerializedViewKey, SerializedViewKey>
>>> _precedence =
>>>              new HashMap<SerializedViewKey, SerializedViewKey>();
>>>
>>>          // old views will be hold as soft references which will be removed by
>>> @@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends S
>>>                  // into the map.
>>>                  state = null;
>>>              }
>>> -
>>> +
>>>              Integer maxCount = getNumberOfSequentialViewsInSession(context);
>>>              if (maxCount != null)
>>>              {
>>> @@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends S
>>>                    previousKey = _precedence.get(previousKey);
>>>                    count++;
>>>                  } while (previousKey != null && count < maxCount);
>>> -
>>> +
>>>                  if (previousKey != null)
>>>                  {
>>>                      SerializedViewKey keyToRemove = (SerializedViewKey)
>>> previousKey;
>>> @@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends S
>>>                          {
>>>                              _serializedViews.remove(keyToRemove);
>>>                          }
>>> -
>>> +
>>>                          keyToRemove = _precedence.remove(keyToRemove);
>>>                      }  while(keyToRemove != null);
>>>                  }
>>> @@ -680,11 +691,11 @@ class ServerSideStateCacheImpl extends S
>>>              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,
>>> +                    // 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
>>> @@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends S
>>>                  if (_serializedViews.containsKey(key) &&
>>>
>>> !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
>>>                  {
>>> -
>>> +
>>>                      getOldSerializedViewsMap().put(key,
>>> _serializedViews.remove(key));
>>>                  }
>>>                  else
>>> @@ -708,10 +719,10 @@ class ServerSideStateCacheImpl extends S
>>>
>>>          protected Integer getNumberOfSequentialViewsInSession(FacesContext
>>> context)
>>>          {
>>> -            return
>>> WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
>>> +            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
>>> @@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends S
>>>              FacesContext context = FacesContext.getCurrentInstance();
>>>              if (_oldSerializedViews == null && context != null)
>>>              {
>>> -                String cacheMode = getCacheOldViewsInSessionMode(context);
>>> +                String cacheMode = getCacheOldViewsInSessionMode(context);
>>>                  if (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
>>>                  {
>>>                      _oldSerializedViews = new
>>> ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true);
>>> @@ -773,13 +784,13 @@ class ServerSideStateCacheImpl extends S
>>>                      _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
>>> @@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends S
>>>              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;
>>> @@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends S
>>>                  return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
>>>              }
>>>          }
>>> -
>>> +
>>>          public Object get(SerializedViewKey key)
>>>          {
>>>              Object value = _serializedViews.get(key);
>>> @@ -846,7 +857,172 @@ class ServerSideStateCacheImpl extends S
>>>          }
>>>      }
>>>
>>> +    /**
>>> +     * Base implementation where all keys used to identify the state of a view
>>> should
>>> +     * extend.
>>> +     */
>>> +    protected abstract static class SerializedViewKey implements Serializable
>>> +    {
>>> +    }
>>> +
>>> +    /**
>>> +     * Implementation of SerializedViewKey, where the hashCode of the viewId is
>>> used
>>> +     * and the sequenceId is a numeric value.
>>> +     */
>>> +    private static class IntIntSerializedViewKey extends SerializedViewKey
>>> +        implements Serializable
>>> +    {
>>> +        private static final long serialVersionUID = -1170697124386063642L;
>>> +
>>> +        private final int _viewId;
>>> +        private final int _sequenceId;
>>> +
>>> +        public IntIntSerializedViewKey(int viewId, int sequence)
>>> +        {
>>> +            _sequenceId = sequence;
>>> +            _viewId = viewId;
>>> +        }
>>> +
>>> +        @Override
>>> +        public boolean equals(Object obj)
>>> +        {
>>> +            if (obj == null)
>>> +            {
>>> +                return false;
>>> +            }
>>> +            if (getClass() != obj.getClass())
>>> +            {
>>> +                return false;
>>> +            }
>>> +            final IntIntSerializedViewKey other = (IntIntSerializedViewKey)
>>> obj;
>>> +            if (this._viewId != other._viewId)
>>> +            {
>>> +                return false;
>>> +            }
>>> +            if (this._sequenceId != other._sequenceId)
>>> +            {
>>> +                return false;
>>> +            }
>>> +            return true;
>>> +        }
>>> +
>>> +        @Override
>>> +        public int hashCode()
>>> +        {
>>> +            int hash = 7;
>>> +            hash = 83 * hash + this._viewId;
>>> +            hash = 83 * hash + this._sequenceId;
>>> +            return hash;
>>> +        }
>>> +    }
>>> +
>>> +    /**
>>> +     * Implementation of SerializedViewKey, where the hashCode of the viewId is
>>> used
>>> +     * and the sequenceId is a string value.
>>> +     */
>>> +    private static class IntByteArraySerializedViewKey extends
>>> SerializedViewKey
>>> +        implements Serializable
>>> +    {
>>> +        private final int _viewId;
>>> +        private final byte[] _sequenceId;
>>> +
>>> +        public IntByteArraySerializedViewKey(int viewId, byte[] sequence)
>>> +        {
>>> +            _sequenceId = sequence;
>>> +            _viewId = viewId;
>>> +        }
>>> +
>>> +        @Override
>>> +        public boolean equals(Object obj)
>>> +        {
>>> +            if (obj == null)
>>> +            {
>>> +                return false;
>>> +            }
>>> +            if (getClass() != obj.getClass())
>>> +            {
>>> +                return false;
>>> +            }
>>> +            final IntByteArraySerializedViewKey other =
>>> (IntByteArraySerializedViewKey) obj;
>>> +            if (this._viewId != other._viewId)
>>> +            {
>>> +                return false;
>>> +            }
>>> +            if (!Arrays.equals(this._sequenceId, other._sequenceId))
>>> +            {
>>> +                return false;
>>> +            }
>>> +            return true;
>>> +        }
>>> +
>>> +        @Override
>>> +        public int hashCode()
>>> +        {
>>> +            int hash = 5;
>>> +            hash = 37 * hash + this._viewId;
>>> +            hash = 37 * hash + Arrays.hashCode(this._sequenceId);
>>> +            return hash;
>>> +        }
>>> +    }
>>> +
>>> +
>>> +    /**
>>> +     * Implementation of SerializedViewKey, where the viewId and the sequenceId
>>> can be
>>> +     * anything.
>>> +     */
>>> +    private static class ReferenceSerializedViewKey<I,K> extends
>>> SerializedViewKey
>>> +        implements Serializable
>>> +    {
>>> +        private static final long serialVersionUID = -1170697124386063642L;
>>> +
>>> +        private final I _viewId;
>>> +        private final K _sequenceId;
>>>
>>> +        public ReferenceSerializedViewKey()
>>> +        {
>>> +            _sequenceId = null;
>>> +            _viewId = null;
>>> +        }
>>> +        public ReferenceSerializedViewKey(I viewId, K sequence)
>>> +        {
>>> +            _sequenceId = sequence;
>>> +            _viewId = viewId;
>>> +        }
>>> +
>>> +        @Override
>>> +        public boolean equals(Object obj)
>>> +        {
>>> +            if (obj == null)
>>> +            {
>>> +                return false;
>>> +            }
>>> +            if (getClass() != obj.getClass())
>>> +            {
>>> +                return false;
>>> +            }
>>> +            final ReferenceSerializedViewKey<I, K> other =
>>> (ReferenceSerializedViewKey<I, K>) obj;
>>> +            if (this._viewId != other._viewId && (this._viewId == null
>>> || !this._viewId.equals(other._viewId)))
>>> +            {
>>> +                return false;
>>> +            }
>>> +            if (this._sequenceId != other._sequenceId &&
>>> +                (this._sequenceId == null ||
>>> !this._sequenceId.equals(other._sequenceId)))
>>> +            {
>>> +                return false;
>>> +            }
>>> +            return true;
>>> +        }
>>> +
>>> +        @Override
>>> +        public int hashCode()
>>> +        {
>>> +            int hash = 7;
>>> +            hash = 83 * hash + (this._viewId != null ? this._viewId.hashCode()
>>> : 0);
>>> +            hash = 83 * hash + (this._sequenceId != null ?
>>> this._sequenceId.hashCode() : 0);
>>> +            return hash;
>>> +        }
>>> +    }
>>> +
>>>      //------------------------------------- METHOD FROM StateCache
>>> ------------------------------------------------
>>>
>>>      @Override
>>> @@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl extends S
>>>          }
>>>          //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);
>>>      }
>>>
>>> @@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl extends S
>>>      {
>>>          return
>>> getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
>>>      }
>>> -
>>> +
>>>      @Override
>>>      public boolean isWriteStateAfterRenderViewRequired(FacesContext
>>> facesContext)
>>>      {
>>> @@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl extends S
>>>      }
>>>
>>>      //------------------------------------- Custom methods
>>> -----------------------------------------------------
>>> -
>>> +
>>>      private boolean isUseFlashScopePurgeViewsInSession(ExternalContext
>>> externalContext)
>>>      {
>>>          if (_useFlashScopePurgeViewsInSession == null)
>>> @@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl extends S
>>>          }
>>>          return _useFlashScopePurgeViewsInSession;
>>>      }
>>> -
>>> +
>>>      private Integer getNumberOfSequentialViewsInSession(ExternalContext
>>> externalContext)
>>>      {
>>>          if (!_numberOfSequentialViewsInSessionSet)
>>>          {
>>>              _numberOfSequentialViewsInSession =
>>> WebConfigParamUtils.getIntegerInitParameter(
>>> -                    externalContext,
>>> +                    externalContext,
>>>                      NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
>>>              _numberOfSequentialViewsInSessionSet = true;
>>>          }
>>>          return _numberOfSequentialViewsInSession;
>>>      }
>>> -
>>> +
>>>      protected KeyFactory getKeyFactory(FacesContext facesContext)
>>>      {
>>>          //return keyFactory;
>>>          return sessionViewStorageFactory.getKeyFactory();
>>>      }
>>> -
>>> +
>>>      protected SessionViewStorageFactory getSessionViewStorageFactory()
>>>      {
>>>          return sessionViewStorageFactory;
>>>      }
>>> +
>>>
>>> +    protected abstract static class KeyFactory<K, V>
>>> +    {
>>> +
>>> +        /**
>>> +         * Generates a unique key per session
>>> +         *
>>> +         * @param facesContext
>>> +         * @return
>>> +         */
>>> +        public abstract K generateKey(FacesContext facesContext);
>>> +
>>> +        /**
>>> +         * Encode a Key into a value that will be used as view state session
>>> token
>>> +         *
>>> +         * @param key
>>> +         * @return
>>> +         */
>>> +        public abstract V encode(K key);
>>>
>>> +        /**
>>> +         * Decode a view state session token into a key
>>> +         *
>>> +         * @param value
>>> +         * @return
>>> +         */
>>> +        public abstract K decode(V value);
>>> +
>>> +    }
>>> +
>>> +    private static class CounterKeyFactory extends KeyFactory<Integer,
>>> String>
>>> +    {
>>> +        /**
>>> +         * Take the counter from session scope and increment
>>> +         *
>>> +         * @param facesContext
>>> +         * @return
>>> +         */
>>> +        @Override
>>> +        public Integer generateKey(FacesContext facesContext)
>>> +        {
>>> +            ExternalContext externalContext =
>>> facesContext.getExternalContext();
>>> +            Object sessionObj = externalContext.getSession(true);
>>> +            Integer sequence = null;
>>> +            synchronized(sessionObj) // synchronized to increase sequence if
>>> multiple requests
>>> +                                    // are handled at the same time for the
>>> session
>>> +            {
>>> +                Map<String, Object> map =
>>> externalContext.getSessionMap();
>>> +                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);
>>> +            }
>>> +            return sequence;
>>> +        }
>>> +
>>> +        public String encode(Integer sequence)
>>> +        {
>>> +            return Integer.toString(sequence, Character.MAX_RADIX);
>>> +        }
>>> +
>>> +        public Integer decode(String serverStateId)
>>> +        {
>>> +             return Integer.valueOf((String) serverStateId,
>>> Character.MAX_RADIX);
>>> +        }
>>> +    }
>>> +
>>> +    /**
>>> +     * This factory generate a key composed by a counter and a random number.
>>> The
>>> +     * counter ensures uniqueness, and the random number prevents guess the
>>> next
>>> +     * session token.
>>> +     */
>>> +    private static class SecureRandomKeyFactory extends KeyFactory<byte[],
>>> String>
>>> +    {
>>> +        private final SessionIdGenerator sessionIdGenerator;
>>> +        private final int length;
>>> +
>>> +        public SecureRandomKeyFactory(FacesContext facesContext)
>>> +        {
>>> +            length =
>>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>> +                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>> +
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>> +            sessionIdGenerator = new SessionIdGenerator();
>>> +            sessionIdGenerator.setSessionIdLength(length);
>>> +            String secureRandomClass =
>>> WebConfigParamUtils.getStringInitParameter(
>>> +                    facesContext.getExternalContext(),
>>> +
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
>>> +            if (secureRandomClass != null)
>>> +            {
>>> +                sessionIdGenerator.setSecureRandomClass(secureRandomClass);
>>> +            }
>>> +            String secureRandomProvider =
>>> WebConfigParamUtils.getStringInitParameter(
>>> +                    facesContext.getExternalContext(),
>>> +
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
>>> +            if (secureRandomProvider != null)
>>> +            {
>>> +
>>> sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
>>> +            }
>>> +            String secureRandomAlgorithm =
>>> WebConfigParamUtils.getStringInitParameter(
>>> +                    facesContext.getExternalContext(),
>>> +
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
>>> +            if (secureRandomAlgorithm != null)
>>> +            {
>>> +
>>> sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
>>> +            }
>>> +        }
>>> +
>>> +        public Integer generateCounterKey(FacesContext facesContext)
>>> +        {
>>> +            ExternalContext externalContext =
>>> facesContext.getExternalContext();
>>> +            Object sessionObj = externalContext.getSession(true);
>>> +            Integer sequence = null;
>>> +            synchronized(sessionObj) // synchronized to increase sequence if
>>> multiple requests
>>> +                                    // are handled at the same time for the
>>> session
>>> +            {
>>> +                Map<String, Object> map =
>>> externalContext.getSessionMap();
>>> +                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);
>>> +            }
>>> +            return sequence;
>>> +        }
>>> +
>>> +        @Override
>>> +        public byte[] generateKey(FacesContext facesContext)
>>> +        {
>>> +            byte[] array = new byte[length];
>>> +            byte[] key = new byte[length+4];
>>> +
>>> +            sessionIdGenerator.getRandomBytes(array);
>>> +            for (int i = 0; i < array.length; i++)
>>> +            {
>>> +                key[i] = array[i];
>>> +            }
>>> +            int value = generateCounterKey(facesContext);
>>> +            key[array.length] =  (byte) (value >>> 24);
>>> +            key[array.length+1] =  (byte) (value >>> 16);
>>> +            key[array.length+2] =  (byte) (value >>> 8);
>>> +            key[array.length+3] =  (byte) (value);
>>> +
>>> +            return key;
>>> +        }
>>> +
>>> +        @Override
>>> +        public String encode(byte[] key)
>>> +        {
>>> +            return new String(Hex.encodeHex(key));
>>> +        }
>>> +
>>> +        @Override
>>> +        public byte[] decode(String value)
>>> +        {
>>> +            try
>>> +            {
>>> +                return Hex.decodeHex(value.toCharArray());
>>> +            }
>>> +            catch (DecoderException ex)
>>> +            {
>>> +                // Cannot decode, ignore silently, later it will be handled as
>>> +                // ViewExpiredException
>>> +            }
>>> +            return null;
>>> +        }
>>> +    }
>>> +
>>> +    private static class RandomKeyFactory extends KeyFactory<byte[],
>>> String>
>>> +    {
>>> +        private final Random random;
>>> +        private final int length;
>>> +
>>> +        public RandomKeyFactory(FacesContext facesContext)
>>> +        {
>>> +            length =
>>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>> +                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>> +
>>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>> +            random = new Random(((int)System.nanoTime())+this.hashCode());
>>> +        }
>>> +
>>> +        public Integer generateCounterKey(FacesContext facesContext)
>>> +        {
>>> +            ExternalContext externalContext =
>>> facesContext.getExternalContext();
>>> +            Object sessionObj = externalContext.getSession(true);
>>> +            Integer sequence = null;
>>> +            synchronized(sessionObj) // synchronized to increase sequence if
>>> multiple requests
>>> +                                    // are handled at the same time for the
>>> session
>>> +            {
>>> +                Map<String, Object> map =
>>> externalContext.getSessionMap();
>>> +                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);
>>> +            }
>>> +            return sequence;
>>> +        }
>>> +
>>> +        @Override
>>> +        public byte[] generateKey(FacesContext facesContext)
>>> +        {
>>> +            byte[] array = new byte[length];
>>> +            byte[] key = new byte[length+4];
>>> +
>>> +            //sessionIdGenerator.getRandomBytes(array);
>>> +            random.nextBytes(array);
>>> +            for (int i = 0; i < array.length; i++)
>>> +            {
>>> +                key[i] = array[i];
>>> +            }
>>> +            int value = generateCounterKey(facesContext);
>>> +            key[array.length] =  (byte) (value >>> 24);
>>> +            key[array.length+1] =  (byte) (value >>> 16);
>>> +            key[array.length+2] =  (byte) (value >>> 8);
>>> +            key[array.length+3] =  (byte) (value);
>>> +
>>> +            return key;
>>> +        }
>>> +
>>> +        @Override
>>> +        public String encode(byte[] key)
>>> +        {
>>> +            return new String(Hex.encodeHex(key));
>>> +        }
>>> +
>>> +        @Override
>>> +        public byte[] decode(String value)
>>> +        {
>>> +            try
>>> +            {
>>> +                return Hex.decodeHex(value.toCharArray());
>>> +            }
>>> +            catch (DecoderException ex)
>>> +            {
>>> +                // Cannot decode, ignore silently, later it will be handled as
>>> +                // ViewExpiredException
>>> +            }
>>> +            return null;
>>> +        }
>>> +    }
>>> +
>>> +    /**
>>> +     *
>>> +     * @param <T>
>>> +     * @param <K>
>>> +     * @param <V>
>>> +     */
>>> +    protected abstract static class SessionViewStorageFactory <T extends
>>> KeyFactory<K,V>, K, V >
>>> +    {
>>> +        private KeyFactory<K, V> keyFactory;
>>> +
>>> +        public SessionViewStorageFactory(KeyFactory<K, V> keyFactory)
>>> +        {
>>> +            this.keyFactory = keyFactory;
>>> +        }
>>> +
>>> +        public KeyFactory<K, V> getKeyFactory()
>>> +        {
>>> +            return keyFactory;
>>> +        }
>>> +
>>> +        public abstract SerializedViewCollection
>>> createSerializedViewCollection(
>>> +                FacesContext context);
>>> +
>>> +        public abstract SerializedViewKey createSerializedViewKey(
>>> +                FacesContext facesContext, String viewId, K key);
>>> +
>>> +    }
>>> +
>>> +    private static class CounterSessionViewStorageFactory
>>> +        extends SessionViewStorageFactory <KeyFactory
>>> <Integer,String>, Integer, String>
>>> +    {
>>> +        public CounterSessionViewStorageFactory(KeyFactory<Integer,
>>> String> keyFactory)
>>> +        {
>>> +            super(keyFactory);
>>> +        }
>>> +
>>> +        @Override
>>> +        public SerializedViewCollection createSerializedViewCollection(
>>> +                FacesContext context)
>>> +        {
>>> +            return new SerializedViewCollection();
>>> +        }
>>> +
>>> +        @Override
>>> +        public SerializedViewKey createSerializedViewKey(
>>> +                FacesContext context, String viewId, Integer key)
>>> +        {
>>> +            if (context.isProjectStage(ProjectStage.Production))
>>> +            {
>>> +                return new IntIntSerializedViewKey(viewId.hashCode(), key);
>>> +            }
>>> +            else
>>> +            {
>>> +                return new ReferenceSerializedViewKey(viewId, key);
>>> +            }
>>> +        }
>>> +    }
>>> +
>>> +    private static class RandomSessionViewStorageFactory
>>> +        extends SessionViewStorageFactory <KeyFactory <byte[],String>,
>>> byte[], String>
>>> +    {
>>> +        public RandomSessionViewStorageFactory(KeyFactory<byte[], String>
>>> keyFactory)
>>> +        {
>>> +            super(keyFactory);
>>> +        }
>>> +
>>> +        @Override
>>> +        public SerializedViewCollection createSerializedViewCollection(
>>> +                FacesContext context)
>>> +        {
>>> +            return new SerializedViewCollection();
>>> +        }
>>> +
>>> +        @Override
>>> +        public SerializedViewKey createSerializedViewKey(
>>> +                FacesContext context, String viewId, byte[] key)
>>> +        {
>>> +            if (context.isProjectStage(ProjectStage.Production))
>>> +            {
>>> +                return new IntByteArraySerializedViewKey(viewId.hashCode(),
>>> key);
>>> +            }
>>> +            else
>>> +            {
>>> +                return new ReferenceSerializedViewKey(viewId, key);
>>> +            }
>>> +        }
>>> +    }
>>> }
>>>

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Leonardo Uribe <lu...@gmail.com>.
2012/11/14 Mark Struberg <st...@yahoo.de>:
> That is ONE strategy! There are tons of others. Plus half of your 10++ inner classes was waste of code!
>
> If you do it pluggable, then do it for real!

Pluggability is not a concern there. It was done in that way to make
the distinction
between the key stored into session map and the interactions required by the
algorithm (decode, encode and so on). Before that, the code was a real mess.
Now it is possible to undestand the difference and make thinks like add a random
fragment and so on.

>
> If the viewId is not needed then let's get rid of it COMPLETELY!
>
> It just doesn't make sense to only use the hashCode. Plus the encryption of that stuff takes SOOOOO much more resources that it just makes no sense to spare a few bytes.
>

Really the only case where we have so many inner classes inside a class is
ServerSideStateCacheImpl . The curious part is the checkstyle rules (set in
strict mode months ago) never detected this as a bad practice.

>
> LieGrue,
> strub
>
>
>
> ----- Original Message -----
>> From: Leonardo Uribe <lu...@gmail.com>
>> To: MyFaces Development <de...@myfaces.apache.org>; Mark Struberg <st...@yahoo.de>
>> Cc:
>> Sent: Wednesday, November 14, 2012 11:24 PM
>> Subject: Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/
>>
>> Hi
>>
>> 2012/11/14 Mark Struberg <st...@yahoo.de>:
>>>  Leo, there was a reason I removed it.
>>>
>>>
>>>  Even after discussing this over 10 mails in a private thread you don't
>> get it it seems. I will open a VOTE about principal design fundamentals and we
>> will act according to this.
>>>
>>>  Just you be prepated: A HASH IS NOT UNIQUE!
>>>
>>
>> But I have told you multiple times, the algorithm does not rely on the
>> hash to be unique, relies on the counter.
>>
>>>  Also saying in the mails you understand and then doing the same crazy code
>> again is just plain ******
>>>
>>>  I gonna revert it now and will write up the VOTE
>>
>> The best way to resolve this is putting the arguments on the table and
>> vote over that, right? after the vote we can do the necessary changes
>> over the code. I have committed the fix that I suppose is correct.
>>
>> regards,
>>
>> Leonardo
>>
>>>
>>>  LieGrue,
>>>  strub
>>>
>>>
>>>
>>>
>>>  ----- Original Message -----
>>>>  From: "lu4242@apache.org" <lu...@apache.org>
>>>>  To: commits@myfaces.apache.org
>>>>  Cc:
>>>>  Sent: Wednesday, November 14, 2012 10:23 PM
>>>>  Subject: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./
>> src/main/java/org/apache/myfaces/renderkit/
>>>>
>>>>  Author: lu4242
>>>>  Date: Wed Nov 14 21:23:35 2012
>>>>  New Revision: 1409414
>>>>
>>>>  URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
>>>>  Log:
>>>>  MYFACES-3638 revert commit 1408993 to include later solution without
>>>>  refactoring.
>>>>
>>>>  Added:
>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>        - copied unchanged from r1408992,
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>>  Removed:
>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
>>>>  Modified:
>>>>      myfaces/core/trunk/impl/   (props changed)
>>>>
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>
>>>>  Propchange: myfaces/core/trunk/impl/
>>>>
>> ------------------------------------------------------------------------------
>>>>  --- svn:ignore (original)
>>>>  +++ svn:ignore Wed Nov 14 21:23:35 2012
>>>>  @@ -7,7 +7,8 @@ target
>>>>  *.iml
>>>>  *.ipr
>>>>  *.iws
>>>>  -.idea
>>>>  .settings
>>>>  +
>>>>  cobertura.ser
>>>>  +
>>>>  test-output
>>>>
>>>>  Modified:
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>  URL:
>>>>
>> http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
>>>>
>> ==============================================================================
>>>>  ---
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>  (original)
>>>>  +++
>>>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>>  Wed Nov 14 21:23:35 2012
>>>>  @@ -30,16 +30,21 @@ import java.security.AccessController;
>>>>  import java.security.PrivilegedActionException;
>>>>  import java.security.PrivilegedExceptionAction;
>>>>  import java.util.ArrayList;
>>>>  +import java.util.Arrays;
>>>>  import java.util.HashMap;
>>>>  import java.util.List;
>>>>  import java.util.Map;
>>>>  +import java.util.Random;
>>>>  import java.util.logging.Level;
>>>>  import java.util.logging.Logger;
>>>>  import java.util.zip.GZIPInputStream;
>>>>  import java.util.zip.GZIPOutputStream;
>>>>  +import javax.faces.application.ProjectStage;
>>>>
>>>>  import javax.faces.context.ExternalContext;
>>>>  import javax.faces.context.FacesContext;
>>>>  +import org.apache.commons.codec.DecoderException;
>>>>  +import org.apache.commons.codec.binary.Hex;
>>>>
>>>>  import org.apache.commons.collections.map.AbstractReferenceMap;
>>>>  import org.apache.commons.collections.map.ReferenceMap;
>>>>  @@ -52,22 +57,22 @@ import org.apache.myfaces.shared.util.We
>>>>  class ServerSideStateCacheImpl extends StateCache<Object, Object>
>>>>  {
>>>>       private static final Logger log =
>>>>  Logger.getLogger(ServerSideStateCacheImpl.class.getName());
>>>>  -
>>>>  -    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>>>  +
>>>>  +    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>>>           ServerSideStateCacheImpl.class.getName() +
>>>>  ".SERIALIZED_VIEW";
>>>>  -
>>>>  -    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR
>> =
>>>>  +
>>>>  +    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR
>> =
>>>>           ServerSideStateCacheImpl.class.getName() +
>>>>  ".RESTORED_SERIALIZED_VIEW";
>>>>
>>>>  -    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>  +    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>>           ServerSideStateCacheImpl.class.getName() +
>>>>  ".RESTORED_VIEW_KEY";
>>>>  -
>>>>  +
>>>>       /**
>>>>        * Defines the amount (default = 20) of the latest views are
>> stored in
>>>>  session.
>>>>  -     *
>>>>  +     *
>>>>        * <p>Only applicable if state saving method is
>> "server" (=
>>>>  default).
>>>>        * </p>
>>>>  -     *
>>>>  +     *
>>>>        */
>>>>
>> @JSFWebConfigParam(defaultValue="20",since="1.1",
>>>>  classType="java.lang.Integer", group="state",
>>>>  tags="performance")
>>>>       private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM =
>>>>  "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
>>>>  @@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
>>>>       /**
>>>>        * 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>Only applicable if state saving method is
>> "server" (=
>>>>  default). For example, if this param has value = 2 and
>>>>  +     *
>>>>  +     * <p>Only applicable if state saving method is
>> "server" (=
>>>>  default). 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
>>>>  @@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends S
>>>>       @JSFWebConfigParam(since="2.0.6",
>>>>  classType="java.lang.Integer", group="state",
>>>>  tags="performance")
>>>>       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;
>>>>
>>>>       /**
>>>>  -     * Indicate if the state should be serialized before save it on
>> the
>>>>  session.
>>>>  +     * Indicate if the state should be serialized before save it on
>> the
>>>>  session.
>>>>        * <p>
>>>>        * 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.
>>>>  @@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends S
>>>>
>>>>       /**
>>>>        * Indicates that the serialized state will be compressed before
>> it is
>>>>  written to the session. By default true.
>>>>  -     *
>>>>  +     *
>>>>        * 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.
>>>>  @@ -140,38 +145,38 @@ class ServerSideStateCacheImpl extends S
>>>>        * <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>
>>>>  +     * <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",
>> group="state",
>>>>  tags="performance")
>>>>       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
>>>>  +     * 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";
>>>>
>>>>       /**
>>>>        * 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.
>>>>  -     *
>>>>  +     *
>>>>        * <p>
>>>>        * Only applicable if state saving method is "server" (=
>>>>  default).
>>>>        * The default value is false.</p>
>>>>  @@ -183,84 +188,90 @@ class ServerSideStateCacheImpl extends S
>>>>       private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE =
>>>>  "none";
>>>>       private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM =
>> "secureRandom";
>>>>       private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM =
>>>>  "random";
>>>>  -
>>>>  +
>>>>       /**
>>>>        * Adds a random key to the generated view state session token.
>>>>        */
>>>>  -    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  expectedValues="secureRandom, random, none",
>>>>  +    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  expectedValues="secureRandom, random, none",
>>>>               defaultValue="none", group="state")
>>>>       private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
>>>>               =
>>>>  "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
>>>>  -    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>  +    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>>               RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
>>>>
>>>>       /**
>>>>        * Set the default length of the random key added to the view
>> state session
>>>>  token.
>>>>  -     * By default is 8.
>>>>  +     * By default is 8.
>>>>        */
>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  defaultValue="8", group="state")
>>>>  -    static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>  +    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>>               =
>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
>>>>  -    static final int
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>  +    private static final int
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>>
>>>>       /**
>>>>  -     * Sets the random class to initialize the secure random id
>> generator.
>>>>  +     * Sets the random class to initialize the secure random id
>> generator.
>>>>        * By default it uses java.security.SecureRandom
>>>>        */
>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  group="state")
>>>>  -    static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>  +    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>>               =
>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
>>>>  -
>>>>  +
>>>>       /**
>>>>        * Sets the random provider to initialize the secure random id
>> generator.
>>>>        */
>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  group="state")
>>>>  -    static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>  +    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>>               =
>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
>>>>  -
>>>>  +
>>>>       /**
>>>>  -     * Sets the random algorithm to initialize the secure random id
>> generator.
>>>>  +     * Sets the random algorithm to initialize the secure random id
>> generator.
>>>>        * By default is SHA1PRNG
>>>>        */
>>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>>  defaultValue="SHA1PRNG", group="state")
>>>>  -    static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>  +    private static final String
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>>               =
>>>>
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
>>>>  -
>>>>  -
>>>>  +
>>>>  +
>>>>       private static final int UNCOMPRESSED_FLAG = 0;
>>>>       private static final int COMPRESSED_FLAG = 1;
>>>>  -
>>>>  +
>>>>       private static final Object[] EMPTY_STATES = new Object[]{null,
>> null};
>>>>
>>>>  +    //private static final int JSF_SEQUENCE_INDEX = 0;
>>>>  +
>>>>       private Boolean _useFlashScopePurgeViewsInSession = null;
>>>>  -
>>>>  +
>>>>       private Integer _numberOfSequentialViewsInSession = null;
>>>>       private boolean _numberOfSequentialViewsInSessionSet = false;
>>>>
>>>>  +    //private final KeyFactory keyFactory;
>>>>       private SessionViewStorageFactory sessionViewStorageFactory;
>>>>
>>>>       public ServerSideStateCacheImpl()
>>>>       {
>>>>           FacesContext facesContext = FacesContext.getCurrentInstance();
>>>>           String randomMode =
>>>>
>> WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
>>>>  -                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>  +                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>>                   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
>>>>           if
>>>>
>> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
>>>>           {
>>>>  -            sessionViewStorageFactory = new SessionViewStorageFactory(
>>>>  +            //keyFactory = new SecureRandomKeyFactory(facesContext);
>>>>  +            sessionViewStorageFactory = new
>> RandomSessionViewStorageFactory(
>>>>                       new SecureRandomKeyFactory(facesContext));
>>>>           }
>>>>           else if
>>>>  (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
>>>>           {
>>>>  -            sessionViewStorageFactory = new SessionViewStorageFactory(
>>>>  +            //keyFactory = new RandomKeyFactory(facesContext);
>>>>  +            sessionViewStorageFactory = new
>> RandomSessionViewStorageFactory(
>>>>                       new RandomKeyFactory(facesContext));
>>>>           }
>>>>           else
>>>>           {
>>>>  -            sessionViewStorageFactory = new
>> SessionViewStorageFactory(new
>>>>  CounterKeyFactory());
>>>>  +            //keyFactory = new CounterKeyFactory();
>>>>  +            sessionViewStorageFactory = new
>>>>  CounterSessionViewStorageFactory(new CounterKeyFactory());
>>>>           }
>>>>       }
>>>>  -
>>>>  +
>>>>       //------------------------------------- METHODS COPIED FROM
>>>>  JspStateManagerImpl--------------------------------
>>>>
>>>>       protected Object getServerStateId(FacesContext facesContext,
>> Object state)
>>>>  @@ -285,16 +296,16 @@ class ServerSideStateCacheImpl extends S
>>>>           }
>>>>
>>>>           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())
>> &&
>>>>  +                if
>>>>  (isUseFlashScopePurgeViewsInSession(context.getExternalContext())
>> &&
>>>>
>>>>  Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
>>>>
>>>>  .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
>>>>                   {
>>>>  @@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends S
>>>>                   }
>>>>               }
>>>>           }
>>>>  -
>>>>  +
>>>>           SerializedViewKey nextKey =
>>>>  getSessionViewStorageFactory().createSerializedViewKey(
>>>>                   context, context.getViewRoot().getViewId(),
>>>>  getNextViewSequence(context));
>>>>           viewCollection.add(context, serializeView(context,
>> serializedView),
>>>>  nextKey, key);
>>>>  @@ -339,14 +350,14 @@ class ServerSideStateCacheImpl extends S
>>>>                   }
>>>>               }
>>>>               attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR,
>>>>  serializedView);
>>>>  -
>>>>  +
>>>>               if (getNumberOfSequentialViewsInSession(externalContext)
>> != null
>>>>  &&
>>>>                   getNumberOfSequentialViewsInSession(externalContext)
>>>  0)
>>>>               {
>>>>                   SerializedViewKey key =
>> getSessionViewStorageFactory().
>>>>                           createSerializedViewKey(context, viewId,
>> sequence);
>>>>                   attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
>>>>  -
>>>>  +
>>>>                   if
>> (isUseFlashScopePurgeViewsInSession(externalContext))
>>>>                   {
>>>>
>>>>  externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
>>>>  @@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends S
>>>>                   //Object[] stateArray = (Object[]) serializedView;
>>>>
>>>>                   ObjectOutputStream out = new ObjectOutputStream(os);
>>>>  -
>>>>  +
>>>>                   out.writeObject(serializedView);
>>>>                   //out.writeObject(stateArray[0]);
>>>>                   //out.writeObject(stateArray[1]);
>>>>  @@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends S
>>>>                       final ObjectInputStream in = new
>>>>  MyFacesObjectInputStream(is);
>>>>                       ois = in;
>>>>                       Object object = null;
>>>>  -                    if (System.getSecurityManager() != null)
>>>>  +                    if (System.getSecurityManager() != null)
>>>>                       {
>>>>  -                        object = AccessController.doPrivileged(new
>>>>  PrivilegedExceptionAction<Object>()
>>>>  +                        object = AccessController.doPrivileged(new
>>>>  PrivilegedExceptionAction<Object>()
>>>>                           {
>>>>                               public Object run() throws
>>>>  PrivilegedActionException, IOException, ClassNotFoundException
>>>>                               {
>>>>  @@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends S
>>>>                       }
>>>>                   }
>>>>               }
>>>>  -            catch (PrivilegedActionException e)
>>>>  +            catch (PrivilegedActionException e)
>>>>               {
>>>>                   log.log(Level.SEVERE, "Exiting deserializeView -
>> Could not
>>>>  deserialize state: " + e.getMessage(), e);
>>>>                   return null;
>>>>  @@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends S
>>>>               return null;
>>>>           }
>>>>       }
>>>>  -
>>>>  +
>>>>       protected static class SerializedViewCollection implements
>> Serializable
>>>>       {
>>>>           private static final long serialVersionUID =
>> -3734849062185115847L;
>>>>  @@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends S
>>>>           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 =
>>>>  +
>>>>  +        private final Map<SerializedViewKey, SerializedViewKey>
>>>>  _precedence =
>>>>               new HashMap<SerializedViewKey, SerializedViewKey>();
>>>>
>>>>           // old views will be hold as soft references which will be
>> removed by
>>>>  @@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends S
>>>>                   // into the map.
>>>>                   state = null;
>>>>               }
>>>>  -
>>>>  +
>>>>               Integer maxCount =
>> getNumberOfSequentialViewsInSession(context);
>>>>               if (maxCount != null)
>>>>               {
>>>>  @@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends S
>>>>                     previousKey = _precedence.get(previousKey);
>>>>                     count++;
>>>>                   } while (previousKey != null && count <
>> maxCount);
>>>>  -
>>>>  +
>>>>                   if (previousKey != null)
>>>>                   {
>>>>                       SerializedViewKey keyToRemove =
>> (SerializedViewKey)
>>>>  previousKey;
>>>>  @@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends S
>>>>                           {
>>>>                               _serializedViews.remove(keyToRemove);
>>>>                           }
>>>>  -
>>>>  +
>>>>                           keyToRemove = _precedence.remove(keyToRemove);
>>>>                       }  while(keyToRemove != null);
>>>>                   }
>>>>  @@ -680,11 +691,11 @@ class ServerSideStateCacheImpl extends S
>>>>               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,
>>>>  +                    // 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
>>>>  @@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends S
>>>>                   if (_serializedViews.containsKey(key) &&
>>>>
>>>>
>> !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
>>>>                   {
>>>>  -
>>>>  +
>>>>                       getOldSerializedViewsMap().put(key,
>>>>  _serializedViews.remove(key));
>>>>                   }
>>>>                   else
>>>>  @@ -708,10 +719,10 @@ class ServerSideStateCacheImpl extends S
>>>>
>>>>           protected Integer
>> getNumberOfSequentialViewsInSession(FacesContext
>>>>  context)
>>>>           {
>>>>  -            return
>>>>
>> WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
>>>>  +            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
>>>>  @@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends S
>>>>               FacesContext context = FacesContext.getCurrentInstance();
>>>>               if (_oldSerializedViews == null && context !=
>> null)
>>>>               {
>>>>  -                String cacheMode =
>> getCacheOldViewsInSessionMode(context);
>>>>  +                String cacheMode =
>> getCacheOldViewsInSessionMode(context);
>>>>                   if
>> (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
>>>>                   {
>>>>                       _oldSerializedViews = new
>>>>  ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK,
>> true);
>>>>  @@ -773,13 +784,13 @@ class ServerSideStateCacheImpl extends S
>>>>                       _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
>>>>  @@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends S
>>>>               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;
>>>>  @@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends S
>>>>                   return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
>>>>               }
>>>>           }
>>>>  -
>>>>  +
>>>>           public Object get(SerializedViewKey key)
>>>>           {
>>>>               Object value = _serializedViews.get(key);
>>>>  @@ -846,7 +857,172 @@ class ServerSideStateCacheImpl extends S
>>>>           }
>>>>       }
>>>>
>>>>  +    /**
>>>>  +     * Base implementation where all keys used to identify the state
>> of a view
>>>>  should
>>>>  +     * extend.
>>>>  +     */
>>>>  +    protected abstract static class SerializedViewKey implements
>> Serializable
>>>>  +    {
>>>>  +    }
>>>>  +
>>>>  +    /**
>>>>  +     * Implementation of SerializedViewKey, where the hashCode of the
>> viewId is
>>>>  used
>>>>  +     * and the sequenceId is a numeric value.
>>>>  +     */
>>>>  +    private static class IntIntSerializedViewKey extends
>> SerializedViewKey
>>>>  +        implements Serializable
>>>>  +    {
>>>>  +        private static final long serialVersionUID =
>> -1170697124386063642L;
>>>>  +
>>>>  +        private final int _viewId;
>>>>  +        private final int _sequenceId;
>>>>  +
>>>>  +        public IntIntSerializedViewKey(int viewId, int sequence)
>>>>  +        {
>>>>  +            _sequenceId = sequence;
>>>>  +            _viewId = viewId;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public boolean equals(Object obj)
>>>>  +        {
>>>>  +            if (obj == null)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (getClass() != obj.getClass())
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            final IntIntSerializedViewKey other =
>> (IntIntSerializedViewKey)
>>>>  obj;
>>>>  +            if (this._viewId != other._viewId)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (this._sequenceId != other._sequenceId)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            return true;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public int hashCode()
>>>>  +        {
>>>>  +            int hash = 7;
>>>>  +            hash = 83 * hash + this._viewId;
>>>>  +            hash = 83 * hash + this._sequenceId;
>>>>  +            return hash;
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +    /**
>>>>  +     * Implementation of SerializedViewKey, where the hashCode of the
>> viewId is
>>>>  used
>>>>  +     * and the sequenceId is a string value.
>>>>  +     */
>>>>  +    private static class IntByteArraySerializedViewKey extends
>>>>  SerializedViewKey
>>>>  +        implements Serializable
>>>>  +    {
>>>>  +        private final int _viewId;
>>>>  +        private final byte[] _sequenceId;
>>>>  +
>>>>  +        public IntByteArraySerializedViewKey(int viewId, byte[]
>> sequence)
>>>>  +        {
>>>>  +            _sequenceId = sequence;
>>>>  +            _viewId = viewId;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public boolean equals(Object obj)
>>>>  +        {
>>>>  +            if (obj == null)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (getClass() != obj.getClass())
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            final IntByteArraySerializedViewKey other =
>>>>  (IntByteArraySerializedViewKey) obj;
>>>>  +            if (this._viewId != other._viewId)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (!Arrays.equals(this._sequenceId, other._sequenceId))
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            return true;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public int hashCode()
>>>>  +        {
>>>>  +            int hash = 5;
>>>>  +            hash = 37 * hash + this._viewId;
>>>>  +            hash = 37 * hash + Arrays.hashCode(this._sequenceId);
>>>>  +            return hash;
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +
>>>>  +    /**
>>>>  +     * Implementation of SerializedViewKey, where the viewId and the
>> sequenceId
>>>>  can be
>>>>  +     * anything.
>>>>  +     */
>>>>  +    private static class ReferenceSerializedViewKey<I,K> extends
>>>>  SerializedViewKey
>>>>  +        implements Serializable
>>>>  +    {
>>>>  +        private static final long serialVersionUID =
>> -1170697124386063642L;
>>>>  +
>>>>  +        private final I _viewId;
>>>>  +        private final K _sequenceId;
>>>>
>>>>  +        public ReferenceSerializedViewKey()
>>>>  +        {
>>>>  +            _sequenceId = null;
>>>>  +            _viewId = null;
>>>>  +        }
>>>>  +        public ReferenceSerializedViewKey(I viewId, K sequence)
>>>>  +        {
>>>>  +            _sequenceId = sequence;
>>>>  +            _viewId = viewId;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public boolean equals(Object obj)
>>>>  +        {
>>>>  +            if (obj == null)
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (getClass() != obj.getClass())
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            final ReferenceSerializedViewKey<I, K> other =
>>>>  (ReferenceSerializedViewKey<I, K>) obj;
>>>>  +            if (this._viewId != other._viewId && (this._viewId
>> == null
>>>>  || !this._viewId.equals(other._viewId)))
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            if (this._sequenceId != other._sequenceId &&
>>>>  +                (this._sequenceId == null ||
>>>>  !this._sequenceId.equals(other._sequenceId)))
>>>>  +            {
>>>>  +                return false;
>>>>  +            }
>>>>  +            return true;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public int hashCode()
>>>>  +        {
>>>>  +            int hash = 7;
>>>>  +            hash = 83 * hash + (this._viewId != null ?
>> this._viewId.hashCode()
>>>>  : 0);
>>>>  +            hash = 83 * hash + (this._sequenceId != null ?
>>>>  this._sequenceId.hashCode() : 0);
>>>>  +            return hash;
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>       //------------------------------------- METHOD FROM StateCache
>>>>  ------------------------------------------------
>>>>
>>>>       @Override
>>>>  @@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl extends S
>>>>           }
>>>>           //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);
>>>>       }
>>>>
>>>>  @@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl extends S
>>>>       {
>>>>           return
>>>>  getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
>>>>       }
>>>>  -
>>>>  +
>>>>       @Override
>>>>       public boolean isWriteStateAfterRenderViewRequired(FacesContext
>>>>  facesContext)
>>>>       {
>>>>  @@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl extends S
>>>>       }
>>>>
>>>>       //------------------------------------- Custom methods
>>>>  -----------------------------------------------------
>>>>  -
>>>>  +
>>>>       private boolean isUseFlashScopePurgeViewsInSession(ExternalContext
>>>>  externalContext)
>>>>       {
>>>>           if (_useFlashScopePurgeViewsInSession == null)
>>>>  @@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl extends S
>>>>           }
>>>>           return _useFlashScopePurgeViewsInSession;
>>>>       }
>>>>  -
>>>>  +
>>>>       private Integer
>> getNumberOfSequentialViewsInSession(ExternalContext
>>>>  externalContext)
>>>>       {
>>>>           if (!_numberOfSequentialViewsInSessionSet)
>>>>           {
>>>>               _numberOfSequentialViewsInSession =
>>>>  WebConfigParamUtils.getIntegerInitParameter(
>>>>  -                    externalContext,
>>>>  +                    externalContext,
>>>>                       NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
>>>>               _numberOfSequentialViewsInSessionSet = true;
>>>>           }
>>>>           return _numberOfSequentialViewsInSession;
>>>>       }
>>>>  -
>>>>  +
>>>>       protected KeyFactory getKeyFactory(FacesContext facesContext)
>>>>       {
>>>>           //return keyFactory;
>>>>           return sessionViewStorageFactory.getKeyFactory();
>>>>       }
>>>>  -
>>>>  +
>>>>       protected SessionViewStorageFactory getSessionViewStorageFactory()
>>>>       {
>>>>           return sessionViewStorageFactory;
>>>>       }
>>>>  +
>>>>
>>>>  +    protected abstract static class KeyFactory<K, V>
>>>>  +    {
>>>>  +
>>>>  +        /**
>>>>  +         * Generates a unique key per session
>>>>  +         *
>>>>  +         * @param facesContext
>>>>  +         * @return
>>>>  +         */
>>>>  +        public abstract K generateKey(FacesContext facesContext);
>>>>  +
>>>>  +        /**
>>>>  +         * Encode a Key into a value that will be used as view state
>> session
>>>>  token
>>>>  +         *
>>>>  +         * @param key
>>>>  +         * @return
>>>>  +         */
>>>>  +        public abstract V encode(K key);
>>>>
>>>>  +        /**
>>>>  +         * Decode a view state session token into a key
>>>>  +         *
>>>>  +         * @param value
>>>>  +         * @return
>>>>  +         */
>>>>  +        public abstract K decode(V value);
>>>>  +
>>>>  +    }
>>>>  +
>>>>  +    private static class CounterKeyFactory extends
>> KeyFactory<Integer,
>>>>  String>
>>>>  +    {
>>>>  +        /**
>>>>  +         * Take the counter from session scope and increment
>>>>  +         *
>>>>  +         * @param facesContext
>>>>  +         * @return
>>>>  +         */
>>>>  +        @Override
>>>>  +        public Integer generateKey(FacesContext facesContext)
>>>>  +        {
>>>>  +            ExternalContext externalContext =
>>>>  facesContext.getExternalContext();
>>>>  +            Object sessionObj = externalContext.getSession(true);
>>>>  +            Integer sequence = null;
>>>>  +            synchronized(sessionObj) // synchronized to increase
>> sequence if
>>>>  multiple requests
>>>>  +                                    // are handled at the same time
>> for the
>>>>  session
>>>>  +            {
>>>>  +                Map<String, Object> map =
>>>>  externalContext.getSessionMap();
>>>>  +                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);
>>>>  +            }
>>>>  +            return sequence;
>>>>  +        }
>>>>  +
>>>>  +        public String encode(Integer sequence)
>>>>  +        {
>>>>  +            return Integer.toString(sequence, Character.MAX_RADIX);
>>>>  +        }
>>>>  +
>>>>  +        public Integer decode(String serverStateId)
>>>>  +        {
>>>>  +             return Integer.valueOf((String) serverStateId,
>>>>  Character.MAX_RADIX);
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +    /**
>>>>  +     * This factory generate a key composed by a counter and a random
>> number.
>>>>  The
>>>>  +     * counter ensures uniqueness, and the random number prevents
>> guess the
>>>>  next
>>>>  +     * session token.
>>>>  +     */
>>>>  +    private static class SecureRandomKeyFactory extends
>> KeyFactory<byte[],
>>>>  String>
>>>>  +    {
>>>>  +        private final SessionIdGenerator sessionIdGenerator;
>>>>  +        private final int length;
>>>>  +
>>>>  +        public SecureRandomKeyFactory(FacesContext facesContext)
>>>>  +        {
>>>>  +            length =
>>>>
>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>  +
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>  +
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>  +            sessionIdGenerator = new SessionIdGenerator();
>>>>  +            sessionIdGenerator.setSessionIdLength(length);
>>>>  +            String secureRandomClass =
>>>>  WebConfigParamUtils.getStringInitParameter(
>>>>  +                    facesContext.getExternalContext(),
>>>>  +
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
>>>>  +            if (secureRandomClass != null)
>>>>  +            {
>>>>  +
>> sessionIdGenerator.setSecureRandomClass(secureRandomClass);
>>>>  +            }
>>>>  +            String secureRandomProvider =
>>>>  WebConfigParamUtils.getStringInitParameter(
>>>>  +                    facesContext.getExternalContext(),
>>>>  +
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
>>>>  +            if (secureRandomProvider != null)
>>>>  +            {
>>>>  +
>>>>  sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
>>>>  +            }
>>>>  +            String secureRandomAlgorithm =
>>>>  WebConfigParamUtils.getStringInitParameter(
>>>>  +                    facesContext.getExternalContext(),
>>>>  +
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
>>>>  +            if (secureRandomAlgorithm != null)
>>>>  +            {
>>>>  +
>>>>  sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
>>>>  +            }
>>>>  +        }
>>>>  +
>>>>  +        public Integer generateCounterKey(FacesContext facesContext)
>>>>  +        {
>>>>  +            ExternalContext externalContext =
>>>>  facesContext.getExternalContext();
>>>>  +            Object sessionObj = externalContext.getSession(true);
>>>>  +            Integer sequence = null;
>>>>  +            synchronized(sessionObj) // synchronized to increase
>> sequence if
>>>>  multiple requests
>>>>  +                                    // are handled at the same time
>> for the
>>>>  session
>>>>  +            {
>>>>  +                Map<String, Object> map =
>>>>  externalContext.getSessionMap();
>>>>  +                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);
>>>>  +            }
>>>>  +            return sequence;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public byte[] generateKey(FacesContext facesContext)
>>>>  +        {
>>>>  +            byte[] array = new byte[length];
>>>>  +            byte[] key = new byte[length+4];
>>>>  +
>>>>  +            sessionIdGenerator.getRandomBytes(array);
>>>>  +            for (int i = 0; i < array.length; i++)
>>>>  +            {
>>>>  +                key[i] = array[i];
>>>>  +            }
>>>>  +            int value = generateCounterKey(facesContext);
>>>>  +            key[array.length] =  (byte) (value >>> 24);
>>>>  +            key[array.length+1] =  (byte) (value >>> 16);
>>>>  +            key[array.length+2] =  (byte) (value >>> 8);
>>>>  +            key[array.length+3] =  (byte) (value);
>>>>  +
>>>>  +            return key;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public String encode(byte[] key)
>>>>  +        {
>>>>  +            return new String(Hex.encodeHex(key));
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public byte[] decode(String value)
>>>>  +        {
>>>>  +            try
>>>>  +            {
>>>>  +                return Hex.decodeHex(value.toCharArray());
>>>>  +            }
>>>>  +            catch (DecoderException ex)
>>>>  +            {
>>>>  +                // Cannot decode, ignore silently, later it will be
>> handled as
>>>>  +                // ViewExpiredException
>>>>  +            }
>>>>  +            return null;
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +    private static class RandomKeyFactory extends
>> KeyFactory<byte[],
>>>>  String>
>>>>  +    {
>>>>  +        private final Random random;
>>>>  +        private final int length;
>>>>  +
>>>>  +        public RandomKeyFactory(FacesContext facesContext)
>>>>  +        {
>>>>  +            length =
>>>>
>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>>  +
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>>  +
>>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>>  +            random = new
>> Random(((int)System.nanoTime())+this.hashCode());
>>>>  +        }
>>>>  +
>>>>  +        public Integer generateCounterKey(FacesContext facesContext)
>>>>  +        {
>>>>  +            ExternalContext externalContext =
>>>>  facesContext.getExternalContext();
>>>>  +            Object sessionObj = externalContext.getSession(true);
>>>>  +            Integer sequence = null;
>>>>  +            synchronized(sessionObj) // synchronized to increase
>> sequence if
>>>>  multiple requests
>>>>  +                                    // are handled at the same time
>> for the
>>>>  session
>>>>  +            {
>>>>  +                Map<String, Object> map =
>>>>  externalContext.getSessionMap();
>>>>  +                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);
>>>>  +            }
>>>>  +            return sequence;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public byte[] generateKey(FacesContext facesContext)
>>>>  +        {
>>>>  +            byte[] array = new byte[length];
>>>>  +            byte[] key = new byte[length+4];
>>>>  +
>>>>  +            //sessionIdGenerator.getRandomBytes(array);
>>>>  +            random.nextBytes(array);
>>>>  +            for (int i = 0; i < array.length; i++)
>>>>  +            {
>>>>  +                key[i] = array[i];
>>>>  +            }
>>>>  +            int value = generateCounterKey(facesContext);
>>>>  +            key[array.length] =  (byte) (value >>> 24);
>>>>  +            key[array.length+1] =  (byte) (value >>> 16);
>>>>  +            key[array.length+2] =  (byte) (value >>> 8);
>>>>  +            key[array.length+3] =  (byte) (value);
>>>>  +
>>>>  +            return key;
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public String encode(byte[] key)
>>>>  +        {
>>>>  +            return new String(Hex.encodeHex(key));
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public byte[] decode(String value)
>>>>  +        {
>>>>  +            try
>>>>  +            {
>>>>  +                return Hex.decodeHex(value.toCharArray());
>>>>  +            }
>>>>  +            catch (DecoderException ex)
>>>>  +            {
>>>>  +                // Cannot decode, ignore silently, later it will be
>> handled as
>>>>  +                // ViewExpiredException
>>>>  +            }
>>>>  +            return null;
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +    /**
>>>>  +     *
>>>>  +     * @param <T>
>>>>  +     * @param <K>
>>>>  +     * @param <V>
>>>>  +     */
>>>>  +    protected abstract static class SessionViewStorageFactory <T
>> extends
>>>>  KeyFactory<K,V>, K, V >
>>>>  +    {
>>>>  +        private KeyFactory<K, V> keyFactory;
>>>>  +
>>>>  +        public SessionViewStorageFactory(KeyFactory<K, V>
>> keyFactory)
>>>>  +        {
>>>>  +            this.keyFactory = keyFactory;
>>>>  +        }
>>>>  +
>>>>  +        public KeyFactory<K, V> getKeyFactory()
>>>>  +        {
>>>>  +            return keyFactory;
>>>>  +        }
>>>>  +
>>>>  +        public abstract SerializedViewCollection
>>>>  createSerializedViewCollection(
>>>>  +                FacesContext context);
>>>>  +
>>>>  +        public abstract SerializedViewKey createSerializedViewKey(
>>>>  +                FacesContext facesContext, String viewId, K key);
>>>>  +
>>>>  +    }
>>>>  +
>>>>  +    private static class CounterSessionViewStorageFactory
>>>>  +        extends SessionViewStorageFactory <KeyFactory
>>>>  <Integer,String>, Integer, String>
>>>>  +    {
>>>>  +        public CounterSessionViewStorageFactory(KeyFactory<Integer,
>>>>  String> keyFactory)
>>>>  +        {
>>>>  +            super(keyFactory);
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public SerializedViewCollection
>> createSerializedViewCollection(
>>>>  +                FacesContext context)
>>>>  +        {
>>>>  +            return new SerializedViewCollection();
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public SerializedViewKey createSerializedViewKey(
>>>>  +                FacesContext context, String viewId, Integer key)
>>>>  +        {
>>>>  +            if (context.isProjectStage(ProjectStage.Production))
>>>>  +            {
>>>>  +                return new IntIntSerializedViewKey(viewId.hashCode(),
>> key);
>>>>  +            }
>>>>  +            else
>>>>  +            {
>>>>  +                return new ReferenceSerializedViewKey(viewId, key);
>>>>  +            }
>>>>  +        }
>>>>  +    }
>>>>  +
>>>>  +    private static class RandomSessionViewStorageFactory
>>>>  +        extends SessionViewStorageFactory <KeyFactory
>> <byte[],String>,
>>>>  byte[], String>
>>>>  +    {
>>>>  +        public RandomSessionViewStorageFactory(KeyFactory<byte[],
>> String>
>>>>  keyFactory)
>>>>  +        {
>>>>  +            super(keyFactory);
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public SerializedViewCollection
>> createSerializedViewCollection(
>>>>  +                FacesContext context)
>>>>  +        {
>>>>  +            return new SerializedViewCollection();
>>>>  +        }
>>>>  +
>>>>  +        @Override
>>>>  +        public SerializedViewKey createSerializedViewKey(
>>>>  +                FacesContext context, String viewId, byte[] key)
>>>>  +        {
>>>>  +            if (context.isProjectStage(ProjectStage.Production))
>>>>  +            {
>>>>  +                return new
>> IntByteArraySerializedViewKey(viewId.hashCode(),
>>>>  key);
>>>>  +            }
>>>>  +            else
>>>>  +            {
>>>>  +                return new ReferenceSerializedViewKey(viewId, key);
>>>>  +            }
>>>>  +        }
>>>>  +    }
>>>>  }
>>>>
>>

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Mark Struberg <st...@yahoo.de>.
That is ONE strategy! There are tons of others. Plus half of your 10++ inner classes was waste of code!

If you do it pluggable, then do it for real!

If the viewId is not needed then let's get rid of it COMPLETELY!

It just doesn't make sense to only use the hashCode. Plus the encryption of that stuff takes SOOOOO much more resources that it just makes no sense to spare a few bytes.


LieGrue,
strub



----- Original Message -----
> From: Leonardo Uribe <lu...@gmail.com>
> To: MyFaces Development <de...@myfaces.apache.org>; Mark Struberg <st...@yahoo.de>
> Cc: 
> Sent: Wednesday, November 14, 2012 11:24 PM
> Subject: Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/
> 
> Hi
> 
> 2012/11/14 Mark Struberg <st...@yahoo.de>:
>>  Leo, there was a reason I removed it.
>> 
>> 
>>  Even after discussing this over 10 mails in a private thread you don't 
> get it it seems. I will open a VOTE about principal design fundamentals and we 
> will act according to this.
>> 
>>  Just you be prepated: A HASH IS NOT UNIQUE!
>> 
> 
> But I have told you multiple times, the algorithm does not rely on the
> hash to be unique, relies on the counter.
> 
>>  Also saying in the mails you understand and then doing the same crazy code 
> again is just plain ******
>> 
>>  I gonna revert it now and will write up the VOTE
> 
> The best way to resolve this is putting the arguments on the table and
> vote over that, right? after the vote we can do the necessary changes
> over the code. I have committed the fix that I suppose is correct.
> 
> regards,
> 
> Leonardo
> 
>> 
>>  LieGrue,
>>  strub
>> 
>> 
>> 
>> 
>>  ----- Original Message -----
>>>  From: "lu4242@apache.org" <lu...@apache.org>
>>>  To: commits@myfaces.apache.org
>>>  Cc:
>>>  Sent: Wednesday, November 14, 2012 10:23 PM
>>>  Subject: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ 
> src/main/java/org/apache/myfaces/renderkit/
>>> 
>>>  Author: lu4242
>>>  Date: Wed Nov 14 21:23:35 2012
>>>  New Revision: 1409414
>>> 
>>>  URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
>>>  Log:
>>>  MYFACES-3638 revert commit 1408993 to include later solution without
>>>  refactoring.
>>> 
>>>  Added:
>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>        - copied unchanged from r1408992,
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>>  Removed:
>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
>>>  Modified:
>>>      myfaces/core/trunk/impl/   (props changed)
>>> 
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>> 
>>>  Propchange: myfaces/core/trunk/impl/
>>> 
> ------------------------------------------------------------------------------
>>>  --- svn:ignore (original)
>>>  +++ svn:ignore Wed Nov 14 21:23:35 2012
>>>  @@ -7,7 +7,8 @@ target
>>>  *.iml
>>>  *.ipr
>>>  *.iws
>>>  -.idea
>>>  .settings
>>>  +
>>>  cobertura.ser
>>>  +
>>>  test-output
>>> 
>>>  Modified:
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>  URL:
>>> 
> http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
>>> 
> ==============================================================================
>>>  ---
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>  (original)
>>>  +++
>>> 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>>  Wed Nov 14 21:23:35 2012
>>>  @@ -30,16 +30,21 @@ import java.security.AccessController;
>>>  import java.security.PrivilegedActionException;
>>>  import java.security.PrivilegedExceptionAction;
>>>  import java.util.ArrayList;
>>>  +import java.util.Arrays;
>>>  import java.util.HashMap;
>>>  import java.util.List;
>>>  import java.util.Map;
>>>  +import java.util.Random;
>>>  import java.util.logging.Level;
>>>  import java.util.logging.Logger;
>>>  import java.util.zip.GZIPInputStream;
>>>  import java.util.zip.GZIPOutputStream;
>>>  +import javax.faces.application.ProjectStage;
>>> 
>>>  import javax.faces.context.ExternalContext;
>>>  import javax.faces.context.FacesContext;
>>>  +import org.apache.commons.codec.DecoderException;
>>>  +import org.apache.commons.codec.binary.Hex;
>>> 
>>>  import org.apache.commons.collections.map.AbstractReferenceMap;
>>>  import org.apache.commons.collections.map.ReferenceMap;
>>>  @@ -52,22 +57,22 @@ import org.apache.myfaces.shared.util.We
>>>  class ServerSideStateCacheImpl extends StateCache<Object, Object>
>>>  {
>>>       private static final Logger log =
>>>  Logger.getLogger(ServerSideStateCacheImpl.class.getName());
>>>  -
>>>  -    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>>  +
>>>  +    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>>           ServerSideStateCacheImpl.class.getName() +
>>>  ".SERIALIZED_VIEW";
>>>  -
>>>  -    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR 
> =
>>>  +
>>>  +    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR 
> =
>>>           ServerSideStateCacheImpl.class.getName() +
>>>  ".RESTORED_SERIALIZED_VIEW";
>>> 
>>>  -    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>  +    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>>           ServerSideStateCacheImpl.class.getName() +
>>>  ".RESTORED_VIEW_KEY";
>>>  -
>>>  +
>>>       /**
>>>        * Defines the amount (default = 20) of the latest views are 
> stored in
>>>  session.
>>>  -     *
>>>  +     *
>>>        * <p>Only applicable if state saving method is 
> "server" (=
>>>  default).
>>>        * </p>
>>>  -     *
>>>  +     *
>>>        */
>>>       
> @JSFWebConfigParam(defaultValue="20",since="1.1",
>>>  classType="java.lang.Integer", group="state",
>>>  tags="performance")
>>>       private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM =
>>>  "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
>>>  @@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
>>>       /**
>>>        * 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>Only applicable if state saving method is 
> "server" (=
>>>  default). For example, if this param has value = 2 and
>>>  +     *
>>>  +     * <p>Only applicable if state saving method is 
> "server" (=
>>>  default). 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
>>>  @@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends S
>>>       @JSFWebConfigParam(since="2.0.6",
>>>  classType="java.lang.Integer", group="state",
>>>  tags="performance")
>>>       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;
>>> 
>>>       /**
>>>  -     * Indicate if the state should be serialized before save it on 
> the
>>>  session.
>>>  +     * Indicate if the state should be serialized before save it on 
> the
>>>  session.
>>>        * <p>
>>>        * 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.
>>>  @@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends S
>>> 
>>>       /**
>>>        * Indicates that the serialized state will be compressed before 
> it is
>>>  written to the session. By default true.
>>>  -     *
>>>  +     *
>>>        * 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.
>>>  @@ -140,38 +145,38 @@ class ServerSideStateCacheImpl extends S
>>>        * <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>
>>>  +     * <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", 
> group="state",
>>>  tags="performance")
>>>       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
>>>  +     * 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";
>>> 
>>>       /**
>>>        * 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.
>>>  -     *
>>>  +     *
>>>        * <p>
>>>        * Only applicable if state saving method is "server" (=
>>>  default).
>>>        * The default value is false.</p>
>>>  @@ -183,84 +188,90 @@ class ServerSideStateCacheImpl extends S
>>>       private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE =
>>>  "none";
>>>       private static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM = 
> "secureRandom";
>>>       private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM =
>>>  "random";
>>>  -
>>>  +
>>>       /**
>>>        * Adds a random key to the generated view state session token.
>>>        */
>>>  -    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>  expectedValues="secureRandom, random, none",
>>>  +    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>  expectedValues="secureRandom, random, none",
>>>               defaultValue="none", group="state")
>>>       private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
>>>               =
>>>  "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
>>>  -    private static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>  +    private static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>>               RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
>>> 
>>>       /**
>>>        * Set the default length of the random key added to the view 
> state session
>>>  token.
>>>  -     * By default is 8.
>>>  +     * By default is 8.
>>>        */
>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>  defaultValue="8", group="state")
>>>  -    static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>  +    private static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>>               =
>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
>>>  -    static final int
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>>  +    private static final int
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>> 
>>>       /**
>>>  -     * Sets the random class to initialize the secure random id 
> generator.
>>>  +     * Sets the random class to initialize the secure random id 
> generator.
>>>        * By default it uses java.security.SecureRandom
>>>        */
>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>  group="state")
>>>  -    static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>  +    private static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>>               =
>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
>>>  -
>>>  +
>>>       /**
>>>        * Sets the random provider to initialize the secure random id 
> generator.
>>>        */
>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>  group="state")
>>>  -    static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>  +    private static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>>               =
>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
>>>  -
>>>  +
>>>       /**
>>>  -     * Sets the random algorithm to initialize the secure random id 
> generator.
>>>  +     * Sets the random algorithm to initialize the secure random id 
> generator.
>>>        * By default is SHA1PRNG
>>>        */
>>>       @JSFWebConfigParam(since="2.1.9, 2.0.15",
>>>  defaultValue="SHA1PRNG", group="state")
>>>  -    static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>  +    private static final String
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>>               =
>>> 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
>>>  -
>>>  -
>>>  +
>>>  +
>>>       private static final int UNCOMPRESSED_FLAG = 0;
>>>       private static final int COMPRESSED_FLAG = 1;
>>>  -
>>>  +
>>>       private static final Object[] EMPTY_STATES = new Object[]{null, 
> null};
>>> 
>>>  +    //private static final int JSF_SEQUENCE_INDEX = 0;
>>>  +
>>>       private Boolean _useFlashScopePurgeViewsInSession = null;
>>>  -
>>>  +
>>>       private Integer _numberOfSequentialViewsInSession = null;
>>>       private boolean _numberOfSequentialViewsInSessionSet = false;
>>> 
>>>  +    //private final KeyFactory keyFactory;
>>>       private SessionViewStorageFactory sessionViewStorageFactory;
>>> 
>>>       public ServerSideStateCacheImpl()
>>>       {
>>>           FacesContext facesContext = FacesContext.getCurrentInstance();
>>>           String randomMode =
>>> 
> WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
>>>  -                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>  +                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>>                   RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
>>>           if
>>> 
> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
>>>           {
>>>  -            sessionViewStorageFactory = new SessionViewStorageFactory(
>>>  +            //keyFactory = new SecureRandomKeyFactory(facesContext);
>>>  +            sessionViewStorageFactory = new 
> RandomSessionViewStorageFactory(
>>>                       new SecureRandomKeyFactory(facesContext));
>>>           }
>>>           else if
>>>  (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
>>>           {
>>>  -            sessionViewStorageFactory = new SessionViewStorageFactory(
>>>  +            //keyFactory = new RandomKeyFactory(facesContext);
>>>  +            sessionViewStorageFactory = new 
> RandomSessionViewStorageFactory(
>>>                       new RandomKeyFactory(facesContext));
>>>           }
>>>           else
>>>           {
>>>  -            sessionViewStorageFactory = new 
> SessionViewStorageFactory(new
>>>  CounterKeyFactory());
>>>  +            //keyFactory = new CounterKeyFactory();
>>>  +            sessionViewStorageFactory = new
>>>  CounterSessionViewStorageFactory(new CounterKeyFactory());
>>>           }
>>>       }
>>>  -
>>>  +
>>>       //------------------------------------- METHODS COPIED FROM
>>>  JspStateManagerImpl--------------------------------
>>> 
>>>       protected Object getServerStateId(FacesContext facesContext, 
> Object state)
>>>  @@ -285,16 +296,16 @@ class ServerSideStateCacheImpl extends S
>>>           }
>>> 
>>>           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()) 
> &&
>>>  +                if
>>>  (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) 
> &&
>>> 
>>>  Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
>>> 
>>>  .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
>>>                   {
>>>  @@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends S
>>>                   }
>>>               }
>>>           }
>>>  -
>>>  +
>>>           SerializedViewKey nextKey =
>>>  getSessionViewStorageFactory().createSerializedViewKey(
>>>                   context, context.getViewRoot().getViewId(),
>>>  getNextViewSequence(context));
>>>           viewCollection.add(context, serializeView(context, 
> serializedView),
>>>  nextKey, key);
>>>  @@ -339,14 +350,14 @@ class ServerSideStateCacheImpl extends S
>>>                   }
>>>               }
>>>               attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR,
>>>  serializedView);
>>>  -
>>>  +
>>>               if (getNumberOfSequentialViewsInSession(externalContext) 
> != null
>>>  &&
>>>                   getNumberOfSequentialViewsInSession(externalContext) 
>>  0)
>>>               {
>>>                   SerializedViewKey key = 
> getSessionViewStorageFactory().
>>>                           createSerializedViewKey(context, viewId, 
> sequence);
>>>                   attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
>>>  -
>>>  +
>>>                   if 
> (isUseFlashScopePurgeViewsInSession(externalContext))
>>>                   {
>>> 
>>>  externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
>>>  @@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends S
>>>                   //Object[] stateArray = (Object[]) serializedView;
>>> 
>>>                   ObjectOutputStream out = new ObjectOutputStream(os);
>>>  -
>>>  +
>>>                   out.writeObject(serializedView);
>>>                   //out.writeObject(stateArray[0]);
>>>                   //out.writeObject(stateArray[1]);
>>>  @@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends S
>>>                       final ObjectInputStream in = new
>>>  MyFacesObjectInputStream(is);
>>>                       ois = in;
>>>                       Object object = null;
>>>  -                    if (System.getSecurityManager() != null)
>>>  +                    if (System.getSecurityManager() != null)
>>>                       {
>>>  -                        object = AccessController.doPrivileged(new
>>>  PrivilegedExceptionAction<Object>()
>>>  +                        object = AccessController.doPrivileged(new
>>>  PrivilegedExceptionAction<Object>()
>>>                           {
>>>                               public Object run() throws
>>>  PrivilegedActionException, IOException, ClassNotFoundException
>>>                               {
>>>  @@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends S
>>>                       }
>>>                   }
>>>               }
>>>  -            catch (PrivilegedActionException e)
>>>  +            catch (PrivilegedActionException e)
>>>               {
>>>                   log.log(Level.SEVERE, "Exiting deserializeView - 
> Could not
>>>  deserialize state: " + e.getMessage(), e);
>>>                   return null;
>>>  @@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends S
>>>               return null;
>>>           }
>>>       }
>>>  -
>>>  +
>>>       protected static class SerializedViewCollection implements 
> Serializable
>>>       {
>>>           private static final long serialVersionUID = 
> -3734849062185115847L;
>>>  @@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends S
>>>           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 =
>>>  +
>>>  +        private final Map<SerializedViewKey, SerializedViewKey>
>>>  _precedence =
>>>               new HashMap<SerializedViewKey, SerializedViewKey>();
>>> 
>>>           // old views will be hold as soft references which will be 
> removed by
>>>  @@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends S
>>>                   // into the map.
>>>                   state = null;
>>>               }
>>>  -
>>>  +
>>>               Integer maxCount = 
> getNumberOfSequentialViewsInSession(context);
>>>               if (maxCount != null)
>>>               {
>>>  @@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends S
>>>                     previousKey = _precedence.get(previousKey);
>>>                     count++;
>>>                   } while (previousKey != null && count < 
> maxCount);
>>>  -
>>>  +
>>>                   if (previousKey != null)
>>>                   {
>>>                       SerializedViewKey keyToRemove = 
> (SerializedViewKey)
>>>  previousKey;
>>>  @@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends S
>>>                           {
>>>                               _serializedViews.remove(keyToRemove);
>>>                           }
>>>  -
>>>  +
>>>                           keyToRemove = _precedence.remove(keyToRemove);
>>>                       }  while(keyToRemove != null);
>>>                   }
>>>  @@ -680,11 +691,11 @@ class ServerSideStateCacheImpl extends S
>>>               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,
>>>  +                    // 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
>>>  @@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends S
>>>                   if (_serializedViews.containsKey(key) &&
>>> 
>>> 
> !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
>>>                   {
>>>  -
>>>  +
>>>                       getOldSerializedViewsMap().put(key,
>>>  _serializedViews.remove(key));
>>>                   }
>>>                   else
>>>  @@ -708,10 +719,10 @@ class ServerSideStateCacheImpl extends S
>>> 
>>>           protected Integer 
> getNumberOfSequentialViewsInSession(FacesContext
>>>  context)
>>>           {
>>>  -            return
>>> 
> WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
>>>  +            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
>>>  @@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends S
>>>               FacesContext context = FacesContext.getCurrentInstance();
>>>               if (_oldSerializedViews == null && context != 
> null)
>>>               {
>>>  -                String cacheMode = 
> getCacheOldViewsInSessionMode(context);
>>>  +                String cacheMode = 
> getCacheOldViewsInSessionMode(context);
>>>                   if 
> (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
>>>                   {
>>>                       _oldSerializedViews = new
>>>  ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, 
> true);
>>>  @@ -773,13 +784,13 @@ class ServerSideStateCacheImpl extends S
>>>                       _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
>>>  @@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends S
>>>               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;
>>>  @@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends S
>>>                   return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
>>>               }
>>>           }
>>>  -
>>>  +
>>>           public Object get(SerializedViewKey key)
>>>           {
>>>               Object value = _serializedViews.get(key);
>>>  @@ -846,7 +857,172 @@ class ServerSideStateCacheImpl extends S
>>>           }
>>>       }
>>> 
>>>  +    /**
>>>  +     * Base implementation where all keys used to identify the state 
> of a view
>>>  should
>>>  +     * extend.
>>>  +     */
>>>  +    protected abstract static class SerializedViewKey implements 
> Serializable
>>>  +    {
>>>  +    }
>>>  +
>>>  +    /**
>>>  +     * Implementation of SerializedViewKey, where the hashCode of the 
> viewId is
>>>  used
>>>  +     * and the sequenceId is a numeric value.
>>>  +     */
>>>  +    private static class IntIntSerializedViewKey extends 
> SerializedViewKey
>>>  +        implements Serializable
>>>  +    {
>>>  +        private static final long serialVersionUID = 
> -1170697124386063642L;
>>>  +
>>>  +        private final int _viewId;
>>>  +        private final int _sequenceId;
>>>  +
>>>  +        public IntIntSerializedViewKey(int viewId, int sequence)
>>>  +        {
>>>  +            _sequenceId = sequence;
>>>  +            _viewId = viewId;
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public boolean equals(Object obj)
>>>  +        {
>>>  +            if (obj == null)
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            if (getClass() != obj.getClass())
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            final IntIntSerializedViewKey other = 
> (IntIntSerializedViewKey)
>>>  obj;
>>>  +            if (this._viewId != other._viewId)
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            if (this._sequenceId != other._sequenceId)
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            return true;
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public int hashCode()
>>>  +        {
>>>  +            int hash = 7;
>>>  +            hash = 83 * hash + this._viewId;
>>>  +            hash = 83 * hash + this._sequenceId;
>>>  +            return hash;
>>>  +        }
>>>  +    }
>>>  +
>>>  +    /**
>>>  +     * Implementation of SerializedViewKey, where the hashCode of the 
> viewId is
>>>  used
>>>  +     * and the sequenceId is a string value.
>>>  +     */
>>>  +    private static class IntByteArraySerializedViewKey extends
>>>  SerializedViewKey
>>>  +        implements Serializable
>>>  +    {
>>>  +        private final int _viewId;
>>>  +        private final byte[] _sequenceId;
>>>  +
>>>  +        public IntByteArraySerializedViewKey(int viewId, byte[] 
> sequence)
>>>  +        {
>>>  +            _sequenceId = sequence;
>>>  +            _viewId = viewId;
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public boolean equals(Object obj)
>>>  +        {
>>>  +            if (obj == null)
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            if (getClass() != obj.getClass())
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            final IntByteArraySerializedViewKey other =
>>>  (IntByteArraySerializedViewKey) obj;
>>>  +            if (this._viewId != other._viewId)
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            if (!Arrays.equals(this._sequenceId, other._sequenceId))
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            return true;
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public int hashCode()
>>>  +        {
>>>  +            int hash = 5;
>>>  +            hash = 37 * hash + this._viewId;
>>>  +            hash = 37 * hash + Arrays.hashCode(this._sequenceId);
>>>  +            return hash;
>>>  +        }
>>>  +    }
>>>  +
>>>  +
>>>  +    /**
>>>  +     * Implementation of SerializedViewKey, where the viewId and the 
> sequenceId
>>>  can be
>>>  +     * anything.
>>>  +     */
>>>  +    private static class ReferenceSerializedViewKey<I,K> extends
>>>  SerializedViewKey
>>>  +        implements Serializable
>>>  +    {
>>>  +        private static final long serialVersionUID = 
> -1170697124386063642L;
>>>  +
>>>  +        private final I _viewId;
>>>  +        private final K _sequenceId;
>>> 
>>>  +        public ReferenceSerializedViewKey()
>>>  +        {
>>>  +            _sequenceId = null;
>>>  +            _viewId = null;
>>>  +        }
>>>  +        public ReferenceSerializedViewKey(I viewId, K sequence)
>>>  +        {
>>>  +            _sequenceId = sequence;
>>>  +            _viewId = viewId;
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public boolean equals(Object obj)
>>>  +        {
>>>  +            if (obj == null)
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            if (getClass() != obj.getClass())
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            final ReferenceSerializedViewKey<I, K> other =
>>>  (ReferenceSerializedViewKey<I, K>) obj;
>>>  +            if (this._viewId != other._viewId && (this._viewId 
> == null
>>>  || !this._viewId.equals(other._viewId)))
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            if (this._sequenceId != other._sequenceId &&
>>>  +                (this._sequenceId == null ||
>>>  !this._sequenceId.equals(other._sequenceId)))
>>>  +            {
>>>  +                return false;
>>>  +            }
>>>  +            return true;
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public int hashCode()
>>>  +        {
>>>  +            int hash = 7;
>>>  +            hash = 83 * hash + (this._viewId != null ? 
> this._viewId.hashCode()
>>>  : 0);
>>>  +            hash = 83 * hash + (this._sequenceId != null ?
>>>  this._sequenceId.hashCode() : 0);
>>>  +            return hash;
>>>  +        }
>>>  +    }
>>>  +
>>>       //------------------------------------- METHOD FROM StateCache
>>>  ------------------------------------------------
>>> 
>>>       @Override
>>>  @@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl extends S
>>>           }
>>>           //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);
>>>       }
>>> 
>>>  @@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl extends S
>>>       {
>>>           return
>>>  getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
>>>       }
>>>  -
>>>  +
>>>       @Override
>>>       public boolean isWriteStateAfterRenderViewRequired(FacesContext
>>>  facesContext)
>>>       {
>>>  @@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl extends S
>>>       }
>>> 
>>>       //------------------------------------- Custom methods
>>>  -----------------------------------------------------
>>>  -
>>>  +
>>>       private boolean isUseFlashScopePurgeViewsInSession(ExternalContext
>>>  externalContext)
>>>       {
>>>           if (_useFlashScopePurgeViewsInSession == null)
>>>  @@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl extends S
>>>           }
>>>           return _useFlashScopePurgeViewsInSession;
>>>       }
>>>  -
>>>  +
>>>       private Integer 
> getNumberOfSequentialViewsInSession(ExternalContext
>>>  externalContext)
>>>       {
>>>           if (!_numberOfSequentialViewsInSessionSet)
>>>           {
>>>               _numberOfSequentialViewsInSession =
>>>  WebConfigParamUtils.getIntegerInitParameter(
>>>  -                    externalContext,
>>>  +                    externalContext,
>>>                       NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
>>>               _numberOfSequentialViewsInSessionSet = true;
>>>           }
>>>           return _numberOfSequentialViewsInSession;
>>>       }
>>>  -
>>>  +
>>>       protected KeyFactory getKeyFactory(FacesContext facesContext)
>>>       {
>>>           //return keyFactory;
>>>           return sessionViewStorageFactory.getKeyFactory();
>>>       }
>>>  -
>>>  +
>>>       protected SessionViewStorageFactory getSessionViewStorageFactory()
>>>       {
>>>           return sessionViewStorageFactory;
>>>       }
>>>  +
>>> 
>>>  +    protected abstract static class KeyFactory<K, V>
>>>  +    {
>>>  +
>>>  +        /**
>>>  +         * Generates a unique key per session
>>>  +         *
>>>  +         * @param facesContext
>>>  +         * @return
>>>  +         */
>>>  +        public abstract K generateKey(FacesContext facesContext);
>>>  +
>>>  +        /**
>>>  +         * Encode a Key into a value that will be used as view state 
> session
>>>  token
>>>  +         *
>>>  +         * @param key
>>>  +         * @return
>>>  +         */
>>>  +        public abstract V encode(K key);
>>> 
>>>  +        /**
>>>  +         * Decode a view state session token into a key
>>>  +         *
>>>  +         * @param value
>>>  +         * @return
>>>  +         */
>>>  +        public abstract K decode(V value);
>>>  +
>>>  +    }
>>>  +
>>>  +    private static class CounterKeyFactory extends 
> KeyFactory<Integer,
>>>  String>
>>>  +    {
>>>  +        /**
>>>  +         * Take the counter from session scope and increment
>>>  +         *
>>>  +         * @param facesContext
>>>  +         * @return
>>>  +         */
>>>  +        @Override
>>>  +        public Integer generateKey(FacesContext facesContext)
>>>  +        {
>>>  +            ExternalContext externalContext =
>>>  facesContext.getExternalContext();
>>>  +            Object sessionObj = externalContext.getSession(true);
>>>  +            Integer sequence = null;
>>>  +            synchronized(sessionObj) // synchronized to increase 
> sequence if
>>>  multiple requests
>>>  +                                    // are handled at the same time 
> for the
>>>  session
>>>  +            {
>>>  +                Map<String, Object> map =
>>>  externalContext.getSessionMap();
>>>  +                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);
>>>  +            }
>>>  +            return sequence;
>>>  +        }
>>>  +
>>>  +        public String encode(Integer sequence)
>>>  +        {
>>>  +            return Integer.toString(sequence, Character.MAX_RADIX);
>>>  +        }
>>>  +
>>>  +        public Integer decode(String serverStateId)
>>>  +        {
>>>  +             return Integer.valueOf((String) serverStateId,
>>>  Character.MAX_RADIX);
>>>  +        }
>>>  +    }
>>>  +
>>>  +    /**
>>>  +     * This factory generate a key composed by a counter and a random 
> number.
>>>  The
>>>  +     * counter ensures uniqueness, and the random number prevents 
> guess the
>>>  next
>>>  +     * session token.
>>>  +     */
>>>  +    private static class SecureRandomKeyFactory extends 
> KeyFactory<byte[],
>>>  String>
>>>  +    {
>>>  +        private final SessionIdGenerator sessionIdGenerator;
>>>  +        private final int length;
>>>  +
>>>  +        public SecureRandomKeyFactory(FacesContext facesContext)
>>>  +        {
>>>  +            length =
>>> 
> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>  +                    
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>  +
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>  +            sessionIdGenerator = new SessionIdGenerator();
>>>  +            sessionIdGenerator.setSessionIdLength(length);
>>>  +            String secureRandomClass =
>>>  WebConfigParamUtils.getStringInitParameter(
>>>  +                    facesContext.getExternalContext(),
>>>  +
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
>>>  +            if (secureRandomClass != null)
>>>  +            {
>>>  +                
> sessionIdGenerator.setSecureRandomClass(secureRandomClass);
>>>  +            }
>>>  +            String secureRandomProvider =
>>>  WebConfigParamUtils.getStringInitParameter(
>>>  +                    facesContext.getExternalContext(),
>>>  +
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
>>>  +            if (secureRandomProvider != null)
>>>  +            {
>>>  +
>>>  sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
>>>  +            }
>>>  +            String secureRandomAlgorithm =
>>>  WebConfigParamUtils.getStringInitParameter(
>>>  +                    facesContext.getExternalContext(),
>>>  +
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
>>>  +            if (secureRandomAlgorithm != null)
>>>  +            {
>>>  +
>>>  sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
>>>  +            }
>>>  +        }
>>>  +
>>>  +        public Integer generateCounterKey(FacesContext facesContext)
>>>  +        {
>>>  +            ExternalContext externalContext =
>>>  facesContext.getExternalContext();
>>>  +            Object sessionObj = externalContext.getSession(true);
>>>  +            Integer sequence = null;
>>>  +            synchronized(sessionObj) // synchronized to increase 
> sequence if
>>>  multiple requests
>>>  +                                    // are handled at the same time 
> for the
>>>  session
>>>  +            {
>>>  +                Map<String, Object> map =
>>>  externalContext.getSessionMap();
>>>  +                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);
>>>  +            }
>>>  +            return sequence;
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public byte[] generateKey(FacesContext facesContext)
>>>  +        {
>>>  +            byte[] array = new byte[length];
>>>  +            byte[] key = new byte[length+4];
>>>  +
>>>  +            sessionIdGenerator.getRandomBytes(array);
>>>  +            for (int i = 0; i < array.length; i++)
>>>  +            {
>>>  +                key[i] = array[i];
>>>  +            }
>>>  +            int value = generateCounterKey(facesContext);
>>>  +            key[array.length] =  (byte) (value >>> 24);
>>>  +            key[array.length+1] =  (byte) (value >>> 16);
>>>  +            key[array.length+2] =  (byte) (value >>> 8);
>>>  +            key[array.length+3] =  (byte) (value);
>>>  +
>>>  +            return key;
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public String encode(byte[] key)
>>>  +        {
>>>  +            return new String(Hex.encodeHex(key));
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public byte[] decode(String value)
>>>  +        {
>>>  +            try
>>>  +            {
>>>  +                return Hex.decodeHex(value.toCharArray());
>>>  +            }
>>>  +            catch (DecoderException ex)
>>>  +            {
>>>  +                // Cannot decode, ignore silently, later it will be 
> handled as
>>>  +                // ViewExpiredException
>>>  +            }
>>>  +            return null;
>>>  +        }
>>>  +    }
>>>  +
>>>  +    private static class RandomKeyFactory extends 
> KeyFactory<byte[],
>>>  String>
>>>  +    {
>>>  +        private final Random random;
>>>  +        private final int length;
>>>  +
>>>  +        public RandomKeyFactory(FacesContext facesContext)
>>>  +        {
>>>  +            length =
>>> 
> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>>>  +                    
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>>>  +
>>>  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>>>  +            random = new 
> Random(((int)System.nanoTime())+this.hashCode());
>>>  +        }
>>>  +
>>>  +        public Integer generateCounterKey(FacesContext facesContext)
>>>  +        {
>>>  +            ExternalContext externalContext =
>>>  facesContext.getExternalContext();
>>>  +            Object sessionObj = externalContext.getSession(true);
>>>  +            Integer sequence = null;
>>>  +            synchronized(sessionObj) // synchronized to increase 
> sequence if
>>>  multiple requests
>>>  +                                    // are handled at the same time 
> for the
>>>  session
>>>  +            {
>>>  +                Map<String, Object> map =
>>>  externalContext.getSessionMap();
>>>  +                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);
>>>  +            }
>>>  +            return sequence;
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public byte[] generateKey(FacesContext facesContext)
>>>  +        {
>>>  +            byte[] array = new byte[length];
>>>  +            byte[] key = new byte[length+4];
>>>  +
>>>  +            //sessionIdGenerator.getRandomBytes(array);
>>>  +            random.nextBytes(array);
>>>  +            for (int i = 0; i < array.length; i++)
>>>  +            {
>>>  +                key[i] = array[i];
>>>  +            }
>>>  +            int value = generateCounterKey(facesContext);
>>>  +            key[array.length] =  (byte) (value >>> 24);
>>>  +            key[array.length+1] =  (byte) (value >>> 16);
>>>  +            key[array.length+2] =  (byte) (value >>> 8);
>>>  +            key[array.length+3] =  (byte) (value);
>>>  +
>>>  +            return key;
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public String encode(byte[] key)
>>>  +        {
>>>  +            return new String(Hex.encodeHex(key));
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public byte[] decode(String value)
>>>  +        {
>>>  +            try
>>>  +            {
>>>  +                return Hex.decodeHex(value.toCharArray());
>>>  +            }
>>>  +            catch (DecoderException ex)
>>>  +            {
>>>  +                // Cannot decode, ignore silently, later it will be 
> handled as
>>>  +                // ViewExpiredException
>>>  +            }
>>>  +            return null;
>>>  +        }
>>>  +    }
>>>  +
>>>  +    /**
>>>  +     *
>>>  +     * @param <T>
>>>  +     * @param <K>
>>>  +     * @param <V>
>>>  +     */
>>>  +    protected abstract static class SessionViewStorageFactory <T 
> extends
>>>  KeyFactory<K,V>, K, V >
>>>  +    {
>>>  +        private KeyFactory<K, V> keyFactory;
>>>  +
>>>  +        public SessionViewStorageFactory(KeyFactory<K, V> 
> keyFactory)
>>>  +        {
>>>  +            this.keyFactory = keyFactory;
>>>  +        }
>>>  +
>>>  +        public KeyFactory<K, V> getKeyFactory()
>>>  +        {
>>>  +            return keyFactory;
>>>  +        }
>>>  +
>>>  +        public abstract SerializedViewCollection
>>>  createSerializedViewCollection(
>>>  +                FacesContext context);
>>>  +
>>>  +        public abstract SerializedViewKey createSerializedViewKey(
>>>  +                FacesContext facesContext, String viewId, K key);
>>>  +
>>>  +    }
>>>  +
>>>  +    private static class CounterSessionViewStorageFactory
>>>  +        extends SessionViewStorageFactory <KeyFactory
>>>  <Integer,String>, Integer, String>
>>>  +    {
>>>  +        public CounterSessionViewStorageFactory(KeyFactory<Integer,
>>>  String> keyFactory)
>>>  +        {
>>>  +            super(keyFactory);
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public SerializedViewCollection 
> createSerializedViewCollection(
>>>  +                FacesContext context)
>>>  +        {
>>>  +            return new SerializedViewCollection();
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public SerializedViewKey createSerializedViewKey(
>>>  +                FacesContext context, String viewId, Integer key)
>>>  +        {
>>>  +            if (context.isProjectStage(ProjectStage.Production))
>>>  +            {
>>>  +                return new IntIntSerializedViewKey(viewId.hashCode(), 
> key);
>>>  +            }
>>>  +            else
>>>  +            {
>>>  +                return new ReferenceSerializedViewKey(viewId, key);
>>>  +            }
>>>  +        }
>>>  +    }
>>>  +
>>>  +    private static class RandomSessionViewStorageFactory
>>>  +        extends SessionViewStorageFactory <KeyFactory 
> <byte[],String>,
>>>  byte[], String>
>>>  +    {
>>>  +        public RandomSessionViewStorageFactory(KeyFactory<byte[], 
> String>
>>>  keyFactory)
>>>  +        {
>>>  +            super(keyFactory);
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public SerializedViewCollection 
> createSerializedViewCollection(
>>>  +                FacesContext context)
>>>  +        {
>>>  +            return new SerializedViewCollection();
>>>  +        }
>>>  +
>>>  +        @Override
>>>  +        public SerializedViewKey createSerializedViewKey(
>>>  +                FacesContext context, String viewId, byte[] key)
>>>  +        {
>>>  +            if (context.isProjectStage(ProjectStage.Production))
>>>  +            {
>>>  +                return new 
> IntByteArraySerializedViewKey(viewId.hashCode(),
>>>  key);
>>>  +            }
>>>  +            else
>>>  +            {
>>>  +                return new ReferenceSerializedViewKey(viewId, key);
>>>  +            }
>>>  +        }
>>>  +    }
>>>  }
>>> 
> 

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Leonardo Uribe <lu...@gmail.com>.
Hi

2012/11/14 Mark Struberg <st...@yahoo.de>:
> Leo, there was a reason I removed it.
>
>
> Even after discussing this over 10 mails in a private thread you don't get it it seems. I will open a VOTE about principal design fundamentals and we will act according to this.
>
> Just you be prepated: A HASH IS NOT UNIQUE!
>

But I have told you multiple times, the algorithm does not rely on the
hash to be unique, relies on the counter.

> Also saying in the mails you understand and then doing the same crazy code again is just plain ******
>
> I gonna revert it now and will write up the VOTE

The best way to resolve this is putting the arguments on the table and
vote over that, right? after the vote we can do the necessary changes
over the code. I have committed the fix that I suppose is correct.

regards,

Leonardo

>
> LieGrue,
> strub
>
>
>
>
> ----- Original Message -----
>> From: "lu4242@apache.org" <lu...@apache.org>
>> To: commits@myfaces.apache.org
>> Cc:
>> Sent: Wednesday, November 14, 2012 10:23 PM
>> Subject: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/
>>
>> Author: lu4242
>> Date: Wed Nov 14 21:23:35 2012
>> New Revision: 1409414
>>
>> URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
>> Log:
>> MYFACES-3638 revert commit 1408993 to include later solution without
>> refactoring.
>>
>> Added:
>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>>       - copied unchanged from r1408992,
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>> Removed:
>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
>> Modified:
>>     myfaces/core/trunk/impl/   (props changed)
>>
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>>
>> Propchange: myfaces/core/trunk/impl/
>> ------------------------------------------------------------------------------
>> --- svn:ignore (original)
>> +++ svn:ignore Wed Nov 14 21:23:35 2012
>> @@ -7,7 +7,8 @@ target
>> *.iml
>> *.ipr
>> *.iws
>> -.idea
>> .settings
>> +
>> cobertura.ser
>> +
>> test-output
>>
>> Modified:
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>> URL:
>> http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
>> ==============================================================================
>> ---
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>> (original)
>> +++
>> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
>> Wed Nov 14 21:23:35 2012
>> @@ -30,16 +30,21 @@ import java.security.AccessController;
>> import java.security.PrivilegedActionException;
>> import java.security.PrivilegedExceptionAction;
>> import java.util.ArrayList;
>> +import java.util.Arrays;
>> import java.util.HashMap;
>> import java.util.List;
>> import java.util.Map;
>> +import java.util.Random;
>> import java.util.logging.Level;
>> import java.util.logging.Logger;
>> import java.util.zip.GZIPInputStream;
>> import java.util.zip.GZIPOutputStream;
>> +import javax.faces.application.ProjectStage;
>>
>> import javax.faces.context.ExternalContext;
>> import javax.faces.context.FacesContext;
>> +import org.apache.commons.codec.DecoderException;
>> +import org.apache.commons.codec.binary.Hex;
>>
>> import org.apache.commons.collections.map.AbstractReferenceMap;
>> import org.apache.commons.collections.map.ReferenceMap;
>> @@ -52,22 +57,22 @@ import org.apache.myfaces.shared.util.We
>> class ServerSideStateCacheImpl extends StateCache<Object, Object>
>> {
>>      private static final Logger log =
>> Logger.getLogger(ServerSideStateCacheImpl.class.getName());
>> -
>> -    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>> +
>> +    private static final String SERIALIZED_VIEW_SESSION_ATTR=
>>          ServerSideStateCacheImpl.class.getName() +
>> ".SERIALIZED_VIEW";
>> -
>> -    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>> +
>> +    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
>>          ServerSideStateCacheImpl.class.getName() +
>> ".RESTORED_SERIALIZED_VIEW";
>>
>> -    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>> +    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
>>          ServerSideStateCacheImpl.class.getName() +
>> ".RESTORED_VIEW_KEY";
>> -
>> +
>>      /**
>>       * Defines the amount (default = 20) of the latest views are stored in
>> session.
>> -     *
>> +     *
>>       * <p>Only applicable if state saving method is "server" (=
>> default).
>>       * </p>
>> -     *
>> +     *
>>       */
>>      @JSFWebConfigParam(defaultValue="20",since="1.1",
>> classType="java.lang.Integer", group="state",
>> tags="performance")
>>      private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM =
>> "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
>> @@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
>>      /**
>>       * 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>Only applicable if state saving method is "server" (=
>> default). For example, if this param has value = 2 and
>> +     *
>> +     * <p>Only applicable if state saving method is "server" (=
>> default). 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
>> @@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends S
>>      @JSFWebConfigParam(since="2.0.6",
>> classType="java.lang.Integer", group="state",
>> tags="performance")
>>      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;
>>
>>      /**
>> -     * Indicate if the state should be serialized before save it on the
>> session.
>> +     * Indicate if the state should be serialized before save it on the
>> session.
>>       * <p>
>>       * 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.
>> @@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends S
>>
>>      /**
>>       * Indicates that the serialized state will be compressed before it is
>> written to the session. By default true.
>> -     *
>> +     *
>>       * 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.
>> @@ -140,38 +145,38 @@ class ServerSideStateCacheImpl extends S
>>       * <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>
>> +     * <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", group="state",
>> tags="performance")
>>      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
>> +     * 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";
>>
>>      /**
>>       * 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.
>> -     *
>> +     *
>>       * <p>
>>       * Only applicable if state saving method is "server" (=
>> default).
>>       * The default value is false.</p>
>> @@ -183,84 +188,90 @@ class ServerSideStateCacheImpl extends S
>>      private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE =
>> "none";
>>      private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM = "secureRandom";
>>      private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM =
>> "random";
>> -
>> +
>>      /**
>>       * Adds a random key to the generated view state session token.
>>       */
>> -    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>> expectedValues="secureRandom, random, none",
>> +    @JSFWebConfigParam(since="2.1.9, 2.0.15",
>> expectedValues="secureRandom, random, none",
>>              defaultValue="none", group="state")
>>      private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
>>              =
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
>> -    private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>> +    private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
>>              RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
>>
>>      /**
>>       * Set the default length of the random key added to the view state session
>> token.
>> -     * By default is 8.
>> +     * By default is 8.
>>       */
>>      @JSFWebConfigParam(since="2.1.9, 2.0.15",
>> defaultValue="8", group="state")
>> -    static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>> +    private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
>>              =
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
>> -    static final int
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>> +    private static final int
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
>>
>>      /**
>> -     * Sets the random class to initialize the secure random id generator.
>> +     * Sets the random class to initialize the secure random id generator.
>>       * By default it uses java.security.SecureRandom
>>       */
>>      @JSFWebConfigParam(since="2.1.9, 2.0.15",
>> group="state")
>> -    static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>> +    private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>>              =
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
>> -
>> +
>>      /**
>>       * Sets the random provider to initialize the secure random id generator.
>>       */
>>      @JSFWebConfigParam(since="2.1.9, 2.0.15",
>> group="state")
>> -    static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>> +    private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>>              =
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
>> -
>> +
>>      /**
>> -     * Sets the random algorithm to initialize the secure random id generator.
>> +     * Sets the random algorithm to initialize the secure random id generator.
>>       * By default is SHA1PRNG
>>       */
>>      @JSFWebConfigParam(since="2.1.9, 2.0.15",
>> defaultValue="SHA1PRNG", group="state")
>> -    static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>> +    private static final String
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
>>              =
>> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
>> -
>> -
>> +
>> +
>>      private static final int UNCOMPRESSED_FLAG = 0;
>>      private static final int COMPRESSED_FLAG = 1;
>> -
>> +
>>      private static final Object[] EMPTY_STATES = new Object[]{null, null};
>>
>> +    //private static final int JSF_SEQUENCE_INDEX = 0;
>> +
>>      private Boolean _useFlashScopePurgeViewsInSession = null;
>> -
>> +
>>      private Integer _numberOfSequentialViewsInSession = null;
>>      private boolean _numberOfSequentialViewsInSessionSet = false;
>>
>> +    //private final KeyFactory keyFactory;
>>      private SessionViewStorageFactory sessionViewStorageFactory;
>>
>>      public ServerSideStateCacheImpl()
>>      {
>>          FacesContext facesContext = FacesContext.getCurrentInstance();
>>          String randomMode =
>> WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
>> -                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>> +                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
>>                  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
>>          if
>> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
>>          {
>> -            sessionViewStorageFactory = new SessionViewStorageFactory(
>> +            //keyFactory = new SecureRandomKeyFactory(facesContext);
>> +            sessionViewStorageFactory = new RandomSessionViewStorageFactory(
>>                      new SecureRandomKeyFactory(facesContext));
>>          }
>>          else if
>> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
>>          {
>> -            sessionViewStorageFactory = new SessionViewStorageFactory(
>> +            //keyFactory = new RandomKeyFactory(facesContext);
>> +            sessionViewStorageFactory = new RandomSessionViewStorageFactory(
>>                      new RandomKeyFactory(facesContext));
>>          }
>>          else
>>          {
>> -            sessionViewStorageFactory = new SessionViewStorageFactory(new
>> CounterKeyFactory());
>> +            //keyFactory = new CounterKeyFactory();
>> +            sessionViewStorageFactory = new
>> CounterSessionViewStorageFactory(new CounterKeyFactory());
>>          }
>>      }
>> -
>> +
>>      //------------------------------------- METHODS COPIED FROM
>> JspStateManagerImpl--------------------------------
>>
>>      protected Object getServerStateId(FacesContext facesContext, Object state)
>> @@ -285,16 +296,16 @@ class ServerSideStateCacheImpl extends S
>>          }
>>
>>          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()) &&
>> +                if
>> (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) &&
>>
>> Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
>>
>> .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
>>                  {
>> @@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends S
>>                  }
>>              }
>>          }
>> -
>> +
>>          SerializedViewKey nextKey =
>> getSessionViewStorageFactory().createSerializedViewKey(
>>                  context, context.getViewRoot().getViewId(),
>> getNextViewSequence(context));
>>          viewCollection.add(context, serializeView(context, serializedView),
>> nextKey, key);
>> @@ -339,14 +350,14 @@ class ServerSideStateCacheImpl extends S
>>                  }
>>              }
>>              attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR,
>> serializedView);
>> -
>> +
>>              if (getNumberOfSequentialViewsInSession(externalContext) != null
>> &&
>>                  getNumberOfSequentialViewsInSession(externalContext) > 0)
>>              {
>>                  SerializedViewKey key = getSessionViewStorageFactory().
>>                          createSerializedViewKey(context, viewId, sequence);
>>                  attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
>> -
>> +
>>                  if (isUseFlashScopePurgeViewsInSession(externalContext))
>>                  {
>>
>> externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
>> @@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends S
>>                  //Object[] stateArray = (Object[]) serializedView;
>>
>>                  ObjectOutputStream out = new ObjectOutputStream(os);
>> -
>> +
>>                  out.writeObject(serializedView);
>>                  //out.writeObject(stateArray[0]);
>>                  //out.writeObject(stateArray[1]);
>> @@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends S
>>                      final ObjectInputStream in = new
>> MyFacesObjectInputStream(is);
>>                      ois = in;
>>                      Object object = null;
>> -                    if (System.getSecurityManager() != null)
>> +                    if (System.getSecurityManager() != null)
>>                      {
>> -                        object = AccessController.doPrivileged(new
>> PrivilegedExceptionAction<Object>()
>> +                        object = AccessController.doPrivileged(new
>> PrivilegedExceptionAction<Object>()
>>                          {
>>                              public Object run() throws
>> PrivilegedActionException, IOException, ClassNotFoundException
>>                              {
>> @@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends S
>>                      }
>>                  }
>>              }
>> -            catch (PrivilegedActionException e)
>> +            catch (PrivilegedActionException e)
>>              {
>>                  log.log(Level.SEVERE, "Exiting deserializeView - Could not
>> deserialize state: " + e.getMessage(), e);
>>                  return null;
>> @@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends S
>>              return null;
>>          }
>>      }
>> -
>> +
>>      protected static class SerializedViewCollection implements Serializable
>>      {
>>          private static final long serialVersionUID = -3734849062185115847L;
>> @@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends S
>>          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 =
>> +
>> +        private final Map<SerializedViewKey, SerializedViewKey>
>> _precedence =
>>              new HashMap<SerializedViewKey, SerializedViewKey>();
>>
>>          // old views will be hold as soft references which will be removed by
>> @@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends S
>>                  // into the map.
>>                  state = null;
>>              }
>> -
>> +
>>              Integer maxCount = getNumberOfSequentialViewsInSession(context);
>>              if (maxCount != null)
>>              {
>> @@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends S
>>                    previousKey = _precedence.get(previousKey);
>>                    count++;
>>                  } while (previousKey != null && count < maxCount);
>> -
>> +
>>                  if (previousKey != null)
>>                  {
>>                      SerializedViewKey keyToRemove = (SerializedViewKey)
>> previousKey;
>> @@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends S
>>                          {
>>                              _serializedViews.remove(keyToRemove);
>>                          }
>> -
>> +
>>                          keyToRemove = _precedence.remove(keyToRemove);
>>                      }  while(keyToRemove != null);
>>                  }
>> @@ -680,11 +691,11 @@ class ServerSideStateCacheImpl extends S
>>              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,
>> +                    // 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
>> @@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends S
>>                  if (_serializedViews.containsKey(key) &&
>>
>> !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
>>                  {
>> -
>> +
>>                      getOldSerializedViewsMap().put(key,
>> _serializedViews.remove(key));
>>                  }
>>                  else
>> @@ -708,10 +719,10 @@ class ServerSideStateCacheImpl extends S
>>
>>          protected Integer getNumberOfSequentialViewsInSession(FacesContext
>> context)
>>          {
>> -            return
>> WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
>> +            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
>> @@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends S
>>              FacesContext context = FacesContext.getCurrentInstance();
>>              if (_oldSerializedViews == null && context != null)
>>              {
>> -                String cacheMode = getCacheOldViewsInSessionMode(context);
>> +                String cacheMode = getCacheOldViewsInSessionMode(context);
>>                  if (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
>>                  {
>>                      _oldSerializedViews = new
>> ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true);
>> @@ -773,13 +784,13 @@ class ServerSideStateCacheImpl extends S
>>                      _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
>> @@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends S
>>              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;
>> @@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends S
>>                  return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
>>              }
>>          }
>> -
>> +
>>          public Object get(SerializedViewKey key)
>>          {
>>              Object value = _serializedViews.get(key);
>> @@ -846,7 +857,172 @@ class ServerSideStateCacheImpl extends S
>>          }
>>      }
>>
>> +    /**
>> +     * Base implementation where all keys used to identify the state of a view
>> should
>> +     * extend.
>> +     */
>> +    protected abstract static class SerializedViewKey implements Serializable
>> +    {
>> +    }
>> +
>> +    /**
>> +     * Implementation of SerializedViewKey, where the hashCode of the viewId is
>> used
>> +     * and the sequenceId is a numeric value.
>> +     */
>> +    private static class IntIntSerializedViewKey extends SerializedViewKey
>> +        implements Serializable
>> +    {
>> +        private static final long serialVersionUID = -1170697124386063642L;
>> +
>> +        private final int _viewId;
>> +        private final int _sequenceId;
>> +
>> +        public IntIntSerializedViewKey(int viewId, int sequence)
>> +        {
>> +            _sequenceId = sequence;
>> +            _viewId = viewId;
>> +        }
>> +
>> +        @Override
>> +        public boolean equals(Object obj)
>> +        {
>> +            if (obj == null)
>> +            {
>> +                return false;
>> +            }
>> +            if (getClass() != obj.getClass())
>> +            {
>> +                return false;
>> +            }
>> +            final IntIntSerializedViewKey other = (IntIntSerializedViewKey)
>> obj;
>> +            if (this._viewId != other._viewId)
>> +            {
>> +                return false;
>> +            }
>> +            if (this._sequenceId != other._sequenceId)
>> +            {
>> +                return false;
>> +            }
>> +            return true;
>> +        }
>> +
>> +        @Override
>> +        public int hashCode()
>> +        {
>> +            int hash = 7;
>> +            hash = 83 * hash + this._viewId;
>> +            hash = 83 * hash + this._sequenceId;
>> +            return hash;
>> +        }
>> +    }
>> +
>> +    /**
>> +     * Implementation of SerializedViewKey, where the hashCode of the viewId is
>> used
>> +     * and the sequenceId is a string value.
>> +     */
>> +    private static class IntByteArraySerializedViewKey extends
>> SerializedViewKey
>> +        implements Serializable
>> +    {
>> +        private final int _viewId;
>> +        private final byte[] _sequenceId;
>> +
>> +        public IntByteArraySerializedViewKey(int viewId, byte[] sequence)
>> +        {
>> +            _sequenceId = sequence;
>> +            _viewId = viewId;
>> +        }
>> +
>> +        @Override
>> +        public boolean equals(Object obj)
>> +        {
>> +            if (obj == null)
>> +            {
>> +                return false;
>> +            }
>> +            if (getClass() != obj.getClass())
>> +            {
>> +                return false;
>> +            }
>> +            final IntByteArraySerializedViewKey other =
>> (IntByteArraySerializedViewKey) obj;
>> +            if (this._viewId != other._viewId)
>> +            {
>> +                return false;
>> +            }
>> +            if (!Arrays.equals(this._sequenceId, other._sequenceId))
>> +            {
>> +                return false;
>> +            }
>> +            return true;
>> +        }
>> +
>> +        @Override
>> +        public int hashCode()
>> +        {
>> +            int hash = 5;
>> +            hash = 37 * hash + this._viewId;
>> +            hash = 37 * hash + Arrays.hashCode(this._sequenceId);
>> +            return hash;
>> +        }
>> +    }
>> +
>> +
>> +    /**
>> +     * Implementation of SerializedViewKey, where the viewId and the sequenceId
>> can be
>> +     * anything.
>> +     */
>> +    private static class ReferenceSerializedViewKey<I,K> extends
>> SerializedViewKey
>> +        implements Serializable
>> +    {
>> +        private static final long serialVersionUID = -1170697124386063642L;
>> +
>> +        private final I _viewId;
>> +        private final K _sequenceId;
>>
>> +        public ReferenceSerializedViewKey()
>> +        {
>> +            _sequenceId = null;
>> +            _viewId = null;
>> +        }
>> +        public ReferenceSerializedViewKey(I viewId, K sequence)
>> +        {
>> +            _sequenceId = sequence;
>> +            _viewId = viewId;
>> +        }
>> +
>> +        @Override
>> +        public boolean equals(Object obj)
>> +        {
>> +            if (obj == null)
>> +            {
>> +                return false;
>> +            }
>> +            if (getClass() != obj.getClass())
>> +            {
>> +                return false;
>> +            }
>> +            final ReferenceSerializedViewKey<I, K> other =
>> (ReferenceSerializedViewKey<I, K>) obj;
>> +            if (this._viewId != other._viewId && (this._viewId == null
>> || !this._viewId.equals(other._viewId)))
>> +            {
>> +                return false;
>> +            }
>> +            if (this._sequenceId != other._sequenceId &&
>> +                (this._sequenceId == null ||
>> !this._sequenceId.equals(other._sequenceId)))
>> +            {
>> +                return false;
>> +            }
>> +            return true;
>> +        }
>> +
>> +        @Override
>> +        public int hashCode()
>> +        {
>> +            int hash = 7;
>> +            hash = 83 * hash + (this._viewId != null ? this._viewId.hashCode()
>> : 0);
>> +            hash = 83 * hash + (this._sequenceId != null ?
>> this._sequenceId.hashCode() : 0);
>> +            return hash;
>> +        }
>> +    }
>> +
>>      //------------------------------------- METHOD FROM StateCache
>> ------------------------------------------------
>>
>>      @Override
>> @@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl extends S
>>          }
>>          //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);
>>      }
>>
>> @@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl extends S
>>      {
>>          return
>> getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
>>      }
>> -
>> +
>>      @Override
>>      public boolean isWriteStateAfterRenderViewRequired(FacesContext
>> facesContext)
>>      {
>> @@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl extends S
>>      }
>>
>>      //------------------------------------- Custom methods
>> -----------------------------------------------------
>> -
>> +
>>      private boolean isUseFlashScopePurgeViewsInSession(ExternalContext
>> externalContext)
>>      {
>>          if (_useFlashScopePurgeViewsInSession == null)
>> @@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl extends S
>>          }
>>          return _useFlashScopePurgeViewsInSession;
>>      }
>> -
>> +
>>      private Integer getNumberOfSequentialViewsInSession(ExternalContext
>> externalContext)
>>      {
>>          if (!_numberOfSequentialViewsInSessionSet)
>>          {
>>              _numberOfSequentialViewsInSession =
>> WebConfigParamUtils.getIntegerInitParameter(
>> -                    externalContext,
>> +                    externalContext,
>>                      NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
>>              _numberOfSequentialViewsInSessionSet = true;
>>          }
>>          return _numberOfSequentialViewsInSession;
>>      }
>> -
>> +
>>      protected KeyFactory getKeyFactory(FacesContext facesContext)
>>      {
>>          //return keyFactory;
>>          return sessionViewStorageFactory.getKeyFactory();
>>      }
>> -
>> +
>>      protected SessionViewStorageFactory getSessionViewStorageFactory()
>>      {
>>          return sessionViewStorageFactory;
>>      }
>> +
>>
>> +    protected abstract static class KeyFactory<K, V>
>> +    {
>> +
>> +        /**
>> +         * Generates a unique key per session
>> +         *
>> +         * @param facesContext
>> +         * @return
>> +         */
>> +        public abstract K generateKey(FacesContext facesContext);
>> +
>> +        /**
>> +         * Encode a Key into a value that will be used as view state session
>> token
>> +         *
>> +         * @param key
>> +         * @return
>> +         */
>> +        public abstract V encode(K key);
>>
>> +        /**
>> +         * Decode a view state session token into a key
>> +         *
>> +         * @param value
>> +         * @return
>> +         */
>> +        public abstract K decode(V value);
>> +
>> +    }
>> +
>> +    private static class CounterKeyFactory extends KeyFactory<Integer,
>> String>
>> +    {
>> +        /**
>> +         * Take the counter from session scope and increment
>> +         *
>> +         * @param facesContext
>> +         * @return
>> +         */
>> +        @Override
>> +        public Integer generateKey(FacesContext facesContext)
>> +        {
>> +            ExternalContext externalContext =
>> facesContext.getExternalContext();
>> +            Object sessionObj = externalContext.getSession(true);
>> +            Integer sequence = null;
>> +            synchronized(sessionObj) // synchronized to increase sequence if
>> multiple requests
>> +                                    // are handled at the same time for the
>> session
>> +            {
>> +                Map<String, Object> map =
>> externalContext.getSessionMap();
>> +                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);
>> +            }
>> +            return sequence;
>> +        }
>> +
>> +        public String encode(Integer sequence)
>> +        {
>> +            return Integer.toString(sequence, Character.MAX_RADIX);
>> +        }
>> +
>> +        public Integer decode(String serverStateId)
>> +        {
>> +             return Integer.valueOf((String) serverStateId,
>> Character.MAX_RADIX);
>> +        }
>> +    }
>> +
>> +    /**
>> +     * This factory generate a key composed by a counter and a random number.
>> The
>> +     * counter ensures uniqueness, and the random number prevents guess the
>> next
>> +     * session token.
>> +     */
>> +    private static class SecureRandomKeyFactory extends KeyFactory<byte[],
>> String>
>> +    {
>> +        private final SessionIdGenerator sessionIdGenerator;
>> +        private final int length;
>> +
>> +        public SecureRandomKeyFactory(FacesContext facesContext)
>> +        {
>> +            length =
>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>> +                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>> +
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>> +            sessionIdGenerator = new SessionIdGenerator();
>> +            sessionIdGenerator.setSessionIdLength(length);
>> +            String secureRandomClass =
>> WebConfigParamUtils.getStringInitParameter(
>> +                    facesContext.getExternalContext(),
>> +
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
>> +            if (secureRandomClass != null)
>> +            {
>> +                sessionIdGenerator.setSecureRandomClass(secureRandomClass);
>> +            }
>> +            String secureRandomProvider =
>> WebConfigParamUtils.getStringInitParameter(
>> +                    facesContext.getExternalContext(),
>> +
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
>> +            if (secureRandomProvider != null)
>> +            {
>> +
>> sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
>> +            }
>> +            String secureRandomAlgorithm =
>> WebConfigParamUtils.getStringInitParameter(
>> +                    facesContext.getExternalContext(),
>> +
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
>> +            if (secureRandomAlgorithm != null)
>> +            {
>> +
>> sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
>> +            }
>> +        }
>> +
>> +        public Integer generateCounterKey(FacesContext facesContext)
>> +        {
>> +            ExternalContext externalContext =
>> facesContext.getExternalContext();
>> +            Object sessionObj = externalContext.getSession(true);
>> +            Integer sequence = null;
>> +            synchronized(sessionObj) // synchronized to increase sequence if
>> multiple requests
>> +                                    // are handled at the same time for the
>> session
>> +            {
>> +                Map<String, Object> map =
>> externalContext.getSessionMap();
>> +                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);
>> +            }
>> +            return sequence;
>> +        }
>> +
>> +        @Override
>> +        public byte[] generateKey(FacesContext facesContext)
>> +        {
>> +            byte[] array = new byte[length];
>> +            byte[] key = new byte[length+4];
>> +
>> +            sessionIdGenerator.getRandomBytes(array);
>> +            for (int i = 0; i < array.length; i++)
>> +            {
>> +                key[i] = array[i];
>> +            }
>> +            int value = generateCounterKey(facesContext);
>> +            key[array.length] =  (byte) (value >>> 24);
>> +            key[array.length+1] =  (byte) (value >>> 16);
>> +            key[array.length+2] =  (byte) (value >>> 8);
>> +            key[array.length+3] =  (byte) (value);
>> +
>> +            return key;
>> +        }
>> +
>> +        @Override
>> +        public String encode(byte[] key)
>> +        {
>> +            return new String(Hex.encodeHex(key));
>> +        }
>> +
>> +        @Override
>> +        public byte[] decode(String value)
>> +        {
>> +            try
>> +            {
>> +                return Hex.decodeHex(value.toCharArray());
>> +            }
>> +            catch (DecoderException ex)
>> +            {
>> +                // Cannot decode, ignore silently, later it will be handled as
>> +                // ViewExpiredException
>> +            }
>> +            return null;
>> +        }
>> +    }
>> +
>> +    private static class RandomKeyFactory extends KeyFactory<byte[],
>> String>
>> +    {
>> +        private final Random random;
>> +        private final int length;
>> +
>> +        public RandomKeyFactory(FacesContext facesContext)
>> +        {
>> +            length =
>> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
>> +                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM,
>> +
>> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
>> +            random = new Random(((int)System.nanoTime())+this.hashCode());
>> +        }
>> +
>> +        public Integer generateCounterKey(FacesContext facesContext)
>> +        {
>> +            ExternalContext externalContext =
>> facesContext.getExternalContext();
>> +            Object sessionObj = externalContext.getSession(true);
>> +            Integer sequence = null;
>> +            synchronized(sessionObj) // synchronized to increase sequence if
>> multiple requests
>> +                                    // are handled at the same time for the
>> session
>> +            {
>> +                Map<String, Object> map =
>> externalContext.getSessionMap();
>> +                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);
>> +            }
>> +            return sequence;
>> +        }
>> +
>> +        @Override
>> +        public byte[] generateKey(FacesContext facesContext)
>> +        {
>> +            byte[] array = new byte[length];
>> +            byte[] key = new byte[length+4];
>> +
>> +            //sessionIdGenerator.getRandomBytes(array);
>> +            random.nextBytes(array);
>> +            for (int i = 0; i < array.length; i++)
>> +            {
>> +                key[i] = array[i];
>> +            }
>> +            int value = generateCounterKey(facesContext);
>> +            key[array.length] =  (byte) (value >>> 24);
>> +            key[array.length+1] =  (byte) (value >>> 16);
>> +            key[array.length+2] =  (byte) (value >>> 8);
>> +            key[array.length+3] =  (byte) (value);
>> +
>> +            return key;
>> +        }
>> +
>> +        @Override
>> +        public String encode(byte[] key)
>> +        {
>> +            return new String(Hex.encodeHex(key));
>> +        }
>> +
>> +        @Override
>> +        public byte[] decode(String value)
>> +        {
>> +            try
>> +            {
>> +                return Hex.decodeHex(value.toCharArray());
>> +            }
>> +            catch (DecoderException ex)
>> +            {
>> +                // Cannot decode, ignore silently, later it will be handled as
>> +                // ViewExpiredException
>> +            }
>> +            return null;
>> +        }
>> +    }
>> +
>> +    /**
>> +     *
>> +     * @param <T>
>> +     * @param <K>
>> +     * @param <V>
>> +     */
>> +    protected abstract static class SessionViewStorageFactory <T extends
>> KeyFactory<K,V>, K, V >
>> +    {
>> +        private KeyFactory<K, V> keyFactory;
>> +
>> +        public SessionViewStorageFactory(KeyFactory<K, V> keyFactory)
>> +        {
>> +            this.keyFactory = keyFactory;
>> +        }
>> +
>> +        public KeyFactory<K, V> getKeyFactory()
>> +        {
>> +            return keyFactory;
>> +        }
>> +
>> +        public abstract SerializedViewCollection
>> createSerializedViewCollection(
>> +                FacesContext context);
>> +
>> +        public abstract SerializedViewKey createSerializedViewKey(
>> +                FacesContext facesContext, String viewId, K key);
>> +
>> +    }
>> +
>> +    private static class CounterSessionViewStorageFactory
>> +        extends SessionViewStorageFactory <KeyFactory
>> <Integer,String>, Integer, String>
>> +    {
>> +        public CounterSessionViewStorageFactory(KeyFactory<Integer,
>> String> keyFactory)
>> +        {
>> +            super(keyFactory);
>> +        }
>> +
>> +        @Override
>> +        public SerializedViewCollection createSerializedViewCollection(
>> +                FacesContext context)
>> +        {
>> +            return new SerializedViewCollection();
>> +        }
>> +
>> +        @Override
>> +        public SerializedViewKey createSerializedViewKey(
>> +                FacesContext context, String viewId, Integer key)
>> +        {
>> +            if (context.isProjectStage(ProjectStage.Production))
>> +            {
>> +                return new IntIntSerializedViewKey(viewId.hashCode(), key);
>> +            }
>> +            else
>> +            {
>> +                return new ReferenceSerializedViewKey(viewId, key);
>> +            }
>> +        }
>> +    }
>> +
>> +    private static class RandomSessionViewStorageFactory
>> +        extends SessionViewStorageFactory <KeyFactory <byte[],String>,
>> byte[], String>
>> +    {
>> +        public RandomSessionViewStorageFactory(KeyFactory<byte[], String>
>> keyFactory)
>> +        {
>> +            super(keyFactory);
>> +        }
>> +
>> +        @Override
>> +        public SerializedViewCollection createSerializedViewCollection(
>> +                FacesContext context)
>> +        {
>> +            return new SerializedViewCollection();
>> +        }
>> +
>> +        @Override
>> +        public SerializedViewKey createSerializedViewKey(
>> +                FacesContext context, String viewId, byte[] key)
>> +        {
>> +            if (context.isProjectStage(ProjectStage.Production))
>> +            {
>> +                return new IntByteArraySerializedViewKey(viewId.hashCode(),
>> key);
>> +            }
>> +            else
>> +            {
>> +                return new ReferenceSerializedViewKey(viewId, key);
>> +            }
>> +        }
>> +    }
>> }
>>

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Mark Struberg <st...@yahoo.de>.
Leo, there was a reason I removed it. 


Even after discussing this over 10 mails in a private thread you don't get it it seems. I will open a VOTE about principal design fundamentals and we will act according to this.

Just you be prepated: A HASH IS NOT UNIQUE!

Also saying in the mails you understand and then doing the same crazy code again is just plain ******

I gonna revert it now and will write up the VOTE

LieGrue,
strub




----- Original Message -----
> From: "lu4242@apache.org" <lu...@apache.org>
> To: commits@myfaces.apache.org
> Cc: 
> Sent: Wednesday, November 14, 2012 10:23 PM
> Subject: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/
> 
> Author: lu4242
> Date: Wed Nov 14 21:23:35 2012
> New Revision: 1409414
> 
> URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
> Log:
> MYFACES-3638 revert commit 1408993 to include later solution without 
> refactoring.
> 
> Added:
>     
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
>       - copied unchanged from r1408992, 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionIdGenerator.java
> Removed:
>     
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/CounterKeyFactory.java
>     
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/KeyFactory.java
>     
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/RandomKeyFactory.java
>     
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SecureRandomKeyFactory.java
>     
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SerializedViewKey.java
>     
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/SessionViewStorageFactory.java
> Modified:
>     myfaces/core/trunk/impl/   (props changed)
>     
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
> 
> Propchange: myfaces/core/trunk/impl/
> ------------------------------------------------------------------------------
> --- svn:ignore (original)
> +++ svn:ignore Wed Nov 14 21:23:35 2012
> @@ -7,7 +7,8 @@ target
> *.iml
> *.ipr
> *.iws
> -.idea
> .settings
> +
> cobertura.ser
> +
> test-output
> 
> Modified: 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
> URL: 
> http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?rev=1409414&r1=1409413&r2=1409414&view=diff
> ==============================================================================
> --- 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java 
> (original)
> +++ 
> myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java 
> Wed Nov 14 21:23:35 2012
> @@ -30,16 +30,21 @@ import java.security.AccessController;
> import java.security.PrivilegedActionException;
> import java.security.PrivilegedExceptionAction;
> import java.util.ArrayList;
> +import java.util.Arrays;
> import java.util.HashMap;
> import java.util.List;
> import java.util.Map;
> +import java.util.Random;
> import java.util.logging.Level;
> import java.util.logging.Logger;
> import java.util.zip.GZIPInputStream;
> import java.util.zip.GZIPOutputStream;
> +import javax.faces.application.ProjectStage;
> 
> import javax.faces.context.ExternalContext;
> import javax.faces.context.FacesContext;
> +import org.apache.commons.codec.DecoderException;
> +import org.apache.commons.codec.binary.Hex;
> 
> import org.apache.commons.collections.map.AbstractReferenceMap;
> import org.apache.commons.collections.map.ReferenceMap;
> @@ -52,22 +57,22 @@ import org.apache.myfaces.shared.util.We
> class ServerSideStateCacheImpl extends StateCache<Object, Object>
> {
>      private static final Logger log = 
> Logger.getLogger(ServerSideStateCacheImpl.class.getName());
> -
> -    private static final String SERIALIZED_VIEW_SESSION_ATTR=
> +    
> +    private static final String SERIALIZED_VIEW_SESSION_ATTR= 
>          ServerSideStateCacheImpl.class.getName() + 
> ".SERIALIZED_VIEW";
> -
> -    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
> +    
> +    private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR = 
>          ServerSideStateCacheImpl.class.getName() + 
> ".RESTORED_SERIALIZED_VIEW";
> 
> -    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
> +    private static final String RESTORED_VIEW_KEY_REQUEST_ATTR = 
>          ServerSideStateCacheImpl.class.getName() + 
> ".RESTORED_VIEW_KEY";
> -
> +    
>      /**
>       * Defines the amount (default = 20) of the latest views are stored in 
> session.
> -     *
> +     * 
>       * <p>Only applicable if state saving method is "server" (= 
> default).
>       * </p>
> -     *
> +     * 
>       */
>      @JSFWebConfigParam(defaultValue="20",since="1.1", 
> classType="java.lang.Integer", group="state", 
> tags="performance")
>      private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM = 
> "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
> @@ -75,8 +80,8 @@ class ServerSideStateCacheImpl extends S
>      /**
>       * 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>Only applicable if state saving method is "server" (= 
> default). For example, if this param has value = 2 and
> +     * 
> +     * <p>Only applicable if state saving method is "server" (= 
> default). 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
> @@ -88,14 +93,14 @@ class ServerSideStateCacheImpl extends S
>      @JSFWebConfigParam(since="2.0.6", 
> classType="java.lang.Integer", group="state", 
> tags="performance")
>      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;
> 
>      /**
> -     * Indicate if the state should be serialized before save it on the 
> session.
> +     * Indicate if the state should be serialized before save it on the 
> session. 
>       * <p>
>       * 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.
> @@ -107,7 +112,7 @@ class ServerSideStateCacheImpl extends S
> 
>      /**
>       * Indicates that the serialized state will be compressed before it is 
> written to the session. By default true.
> -     *
> +     * 
>       * 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.
> @@ -140,38 +145,38 @@ class ServerSideStateCacheImpl extends S
>       * <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>
> +     * <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", group="state", 
> tags="performance")
>      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
> +     * 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";
> 
>      /**
>       * 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.
> -     *
> +     * 
>       * <p>
>       * Only applicable if state saving method is "server" (= 
> default).
>       * The default value is false.</p>
> @@ -183,84 +188,90 @@ class ServerSideStateCacheImpl extends S
>      private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE = 
> "none";
>      private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM = "secureRandom";
>      private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM = 
> "random";
> -
> +    
>      /**
>       * Adds a random key to the generated view state session token.
>       */
> -    @JSFWebConfigParam(since="2.1.9, 2.0.15", 
> expectedValues="secureRandom, random, none",
> +    @JSFWebConfigParam(since="2.1.9, 2.0.15", 
> expectedValues="secureRandom, random, none", 
>              defaultValue="none", group="state")
>      private static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM
>              = 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN";
> -    private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT =
> +    private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT = 
>              RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_NONE;
> 
>      /**
>       * Set the default length of the random key added to the view state session 
> token.
> -     * By default is 8.
> +     * By default is 8. 
>       */
>      @JSFWebConfigParam(since="2.1.9, 2.0.15", 
> defaultValue="8", group="state")
> -    static final String RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM
> +    private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM 
>              = 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH";
> -    static final int 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
> +    private static final int 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT = 8;
> 
>      /**
> -     * Sets the random class to initialize the secure random id generator.
> +     * Sets the random class to initialize the secure random id generator. 
>       * By default it uses java.security.SecureRandom
>       */
>      @JSFWebConfigParam(since="2.1.9, 2.0.15", 
> group="state")
> -    static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
> +    private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM
>              = 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS";
> -
> +    
>      /**
>       * Sets the random provider to initialize the secure random id generator.
>       */
>      @JSFWebConfigParam(since="2.1.9, 2.0.15", 
> group="state")
> -    static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
> +    private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM
>              = 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER";
> -
> +    
>      /**
> -     * Sets the random algorithm to initialize the secure random id generator.
> +     * Sets the random algorithm to initialize the secure random id generator. 
>       * By default is SHA1PRNG
>       */
>      @JSFWebConfigParam(since="2.1.9, 2.0.15", 
> defaultValue="SHA1PRNG", group="state")
> -    static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM
> +    private static final String 
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM 
>              = 
> "org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM";
> -
> -
> +    
> +    
>      private static final int UNCOMPRESSED_FLAG = 0;
>      private static final int COMPRESSED_FLAG = 1;
> -
> +    
>      private static final Object[] EMPTY_STATES = new Object[]{null, null};
> 
> +    //private static final int JSF_SEQUENCE_INDEX = 0;
> +    
>      private Boolean _useFlashScopePurgeViewsInSession = null;
> -
> +    
>      private Integer _numberOfSequentialViewsInSession = null;
>      private boolean _numberOfSequentialViewsInSessionSet = false;
> 
> +    //private final KeyFactory keyFactory;
>      private SessionViewStorageFactory sessionViewStorageFactory;
> 
>      public ServerSideStateCacheImpl()
>      {
>          FacesContext facesContext = FacesContext.getCurrentInstance();
>          String randomMode = 
> WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
> -                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM,
> +                RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM, 
>                  RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_PARAM_DEFAULT);
>          if 
> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM.equals(randomMode))
>          {
> -            sessionViewStorageFactory = new SessionViewStorageFactory(
> +            //keyFactory = new SecureRandomKeyFactory(facesContext);
> +            sessionViewStorageFactory = new RandomSessionViewStorageFactory(
>                      new SecureRandomKeyFactory(facesContext));
>          }
>          else if 
> (RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_RANDOM.equals(randomMode))
>          {
> -            sessionViewStorageFactory = new SessionViewStorageFactory(
> +            //keyFactory = new RandomKeyFactory(facesContext);
> +            sessionViewStorageFactory = new RandomSessionViewStorageFactory(
>                      new RandomKeyFactory(facesContext));
>          }
>          else
>          {
> -            sessionViewStorageFactory = new SessionViewStorageFactory(new 
> CounterKeyFactory());
> +            //keyFactory = new CounterKeyFactory();
> +            sessionViewStorageFactory = new 
> CounterSessionViewStorageFactory(new CounterKeyFactory());
>          }
>      }
> -
> +    
>      //------------------------------------- METHODS COPIED FROM 
> JspStateManagerImpl--------------------------------
> 
>      protected Object getServerStateId(FacesContext facesContext, Object state)
> @@ -285,16 +296,16 @@ class ServerSideStateCacheImpl extends S
>          }
> 
>          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()) &&
> +                if 
> (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) && 
>                     
> Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
>                             
> .get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
>                  {
> @@ -303,7 +314,7 @@ class ServerSideStateCacheImpl extends S
>                  }
>              }
>          }
> -
> +        
>          SerializedViewKey nextKey = 
> getSessionViewStorageFactory().createSerializedViewKey(
>                  context, context.getViewRoot().getViewId(), 
> getNextViewSequence(context));
>          viewCollection.add(context, serializeView(context, serializedView), 
> nextKey, key);
> @@ -339,14 +350,14 @@ class ServerSideStateCacheImpl extends S
>                  }
>              }
>              attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR, 
> serializedView);
> -
> +            
>              if (getNumberOfSequentialViewsInSession(externalContext) != null 
> &&
>                  getNumberOfSequentialViewsInSession(externalContext) > 0)
>              {
>                  SerializedViewKey key = getSessionViewStorageFactory().
>                          createSerializedViewKey(context, viewId, sequence);
>                  attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
> -
> +                
>                  if (isUseFlashScopePurgeViewsInSession(externalContext))
>                  {
>                     
> externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
> @@ -418,7 +429,7 @@ class ServerSideStateCacheImpl extends S
>                  //Object[] stateArray = (Object[]) serializedView;
> 
>                  ObjectOutputStream out = new ObjectOutputStream(os);
> -
> +                
>                  out.writeObject(serializedView);
>                  //out.writeObject(stateArray[0]);
>                  //out.writeObject(stateArray[1]);
> @@ -513,9 +524,9 @@ class ServerSideStateCacheImpl extends S
>                      final ObjectInputStream in = new 
> MyFacesObjectInputStream(is);
>                      ois = in;
>                      Object object = null;
> -                    if (System.getSecurityManager() != null)
> +                    if (System.getSecurityManager() != null) 
>                      {
> -                        object = AccessController.doPrivileged(new 
> PrivilegedExceptionAction<Object>()
> +                        object = AccessController.doPrivileged(new 
> PrivilegedExceptionAction<Object>() 
>                          {
>                              public Object run() throws 
> PrivilegedActionException, IOException, ClassNotFoundException
>                              {
> @@ -540,7 +551,7 @@ class ServerSideStateCacheImpl extends S
>                      }
>                  }
>              }
> -            catch (PrivilegedActionException e)
> +            catch (PrivilegedActionException e) 
>              {
>                  log.log(Level.SEVERE, "Exiting deserializeView - Could not 
> deserialize state: " + e.getMessage(), e);
>                  return null;
> @@ -577,7 +588,7 @@ class ServerSideStateCacheImpl extends S
>              return null;
>          }
>      }
> -
> +    
>      protected static class SerializedViewCollection implements Serializable
>      {
>          private static final long serialVersionUID = -3734849062185115847L;
> @@ -585,8 +596,8 @@ class ServerSideStateCacheImpl extends S
>          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 =
> +        
> +        private final Map<SerializedViewKey, SerializedViewKey> 
> _precedence = 
>              new HashMap<SerializedViewKey, SerializedViewKey>();
> 
>          // old views will be hold as soft references which will be removed by
> @@ -609,7 +620,7 @@ class ServerSideStateCacheImpl extends S
>                  // into the map.
>                  state = null;
>              }
> -
> +            
>              Integer maxCount = getNumberOfSequentialViewsInSession(context);
>              if (maxCount != null)
>              {
> @@ -647,7 +658,7 @@ class ServerSideStateCacheImpl extends S
>                    previousKey = _precedence.get(previousKey);
>                    count++;
>                  } while (previousKey != null && count < maxCount);
> -
> +                
>                  if (previousKey != null)
>                  {
>                      SerializedViewKey keyToRemove = (SerializedViewKey) 
> previousKey;
> @@ -670,7 +681,7 @@ class ServerSideStateCacheImpl extends S
>                          {
>                              _serializedViews.remove(keyToRemove);
>                          }
> -
> +                    
>                          keyToRemove = _precedence.remove(keyToRemove);
>                      }  while(keyToRemove != null);
>                  }
> @@ -680,11 +691,11 @@ class ServerSideStateCacheImpl extends S
>              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,
> +                    // 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
> @@ -696,7 +707,7 @@ class ServerSideStateCacheImpl extends S
>                  if (_serializedViews.containsKey(key) &&
>                     
> !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
>                  {
> -
> +                    
>                      getOldSerializedViewsMap().put(key, 
> _serializedViews.remove(key));
>                  }
>                  else
> @@ -708,10 +719,10 @@ class ServerSideStateCacheImpl extends S
> 
>          protected Integer getNumberOfSequentialViewsInSession(FacesContext 
> context)
>          {
> -            return 
> WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
> +            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
> @@ -755,7 +766,7 @@ class ServerSideStateCacheImpl extends S
>              FacesContext context = FacesContext.getCurrentInstance();
>              if (_oldSerializedViews == null && context != null)
>              {
> -                String cacheMode = getCacheOldViewsInSessionMode(context);
> +                String cacheMode = getCacheOldViewsInSessionMode(context); 
>                  if (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
>                  {
>                      _oldSerializedViews = new 
> ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true);
> @@ -773,13 +784,13 @@ class ServerSideStateCacheImpl extends S
>                      _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
> @@ -800,7 +811,7 @@ class ServerSideStateCacheImpl extends S
>              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;
> @@ -814,7 +825,7 @@ class ServerSideStateCacheImpl extends S
>                  return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
>              }
>          }
> -
> +        
>          public Object get(SerializedViewKey key)
>          {
>              Object value = _serializedViews.get(key);
> @@ -846,7 +857,172 @@ class ServerSideStateCacheImpl extends S
>          }
>      }
> 
> +    /**
> +     * Base implementation where all keys used to identify the state of a view 
> should
> +     * extend.
> +     */
> +    protected abstract static class SerializedViewKey implements Serializable
> +    {
> +    }
> +
> +    /**
> +     * Implementation of SerializedViewKey, where the hashCode of the viewId is 
> used
> +     * and the sequenceId is a numeric value.
> +     */
> +    private static class IntIntSerializedViewKey extends SerializedViewKey 
> +        implements Serializable
> +    {
> +        private static final long serialVersionUID = -1170697124386063642L;
> +        
> +        private final int _viewId;
> +        private final int _sequenceId;
> +        
> +        public IntIntSerializedViewKey(int viewId, int sequence)
> +        {
> +            _sequenceId = sequence;
> +            _viewId = viewId;
> +        }
> +
> +        @Override
> +        public boolean equals(Object obj)
> +        {
> +            if (obj == null)
> +            {
> +                return false;
> +            }
> +            if (getClass() != obj.getClass())
> +            {
> +                return false;
> +            }
> +            final IntIntSerializedViewKey other = (IntIntSerializedViewKey) 
> obj;
> +            if (this._viewId != other._viewId)
> +            {
> +                return false;
> +            }
> +            if (this._sequenceId != other._sequenceId)
> +            {
> +                return false;
> +            }
> +            return true;
> +        }
> +
> +        @Override
> +        public int hashCode()
> +        {
> +            int hash = 7;
> +            hash = 83 * hash + this._viewId;
> +            hash = 83 * hash + this._sequenceId;
> +            return hash;
> +        }
> +    }
> +
> +    /**
> +     * Implementation of SerializedViewKey, where the hashCode of the viewId is 
> used
> +     * and the sequenceId is a string value.
> +     */
> +    private static class IntByteArraySerializedViewKey extends 
> SerializedViewKey
> +        implements Serializable
> +    {
> +        private final int _viewId;
> +        private final byte[] _sequenceId;
> +        
> +        public IntByteArraySerializedViewKey(int viewId, byte[] sequence)
> +        {
> +            _sequenceId = sequence;
> +            _viewId = viewId;
> +        }
> +
> +        @Override
> +        public boolean equals(Object obj)
> +        {
> +            if (obj == null)
> +            {
> +                return false;
> +            }
> +            if (getClass() != obj.getClass())
> +            {
> +                return false;
> +            }
> +            final IntByteArraySerializedViewKey other = 
> (IntByteArraySerializedViewKey) obj;
> +            if (this._viewId != other._viewId)
> +            {
> +                return false;
> +            }
> +            if (!Arrays.equals(this._sequenceId, other._sequenceId))
> +            {
> +                return false;
> +            }
> +            return true;
> +        }
> +
> +        @Override
> +        public int hashCode()
> +        {
> +            int hash = 5;
> +            hash = 37 * hash + this._viewId;
> +            hash = 37 * hash + Arrays.hashCode(this._sequenceId);
> +            return hash;
> +        }
> +    }
> +    
> +    
> +    /**
> +     * Implementation of SerializedViewKey, where the viewId and the sequenceId 
> can be
> +     * anything.
> +     */
> +    private static class ReferenceSerializedViewKey<I,K> extends 
> SerializedViewKey
> +        implements Serializable
> +    {
> +        private static final long serialVersionUID = -1170697124386063642L;
> +
> +        private final I _viewId;
> +        private final K _sequenceId;
> 
> +        public ReferenceSerializedViewKey()
> +        {
> +            _sequenceId = null;
> +            _viewId = null;
> +        }
> +        public ReferenceSerializedViewKey(I viewId, K sequence)
> +        {
> +            _sequenceId = sequence;
> +            _viewId = viewId;
> +        }
> +
> +        @Override
> +        public boolean equals(Object obj)
> +        {
> +            if (obj == null)
> +            {
> +                return false;
> +            }
> +            if (getClass() != obj.getClass())
> +            {
> +                return false;
> +            }
> +            final ReferenceSerializedViewKey<I, K> other = 
> (ReferenceSerializedViewKey<I, K>) obj;
> +            if (this._viewId != other._viewId && (this._viewId == null 
> || !this._viewId.equals(other._viewId)))
> +            {
> +                return false;
> +            }
> +            if (this._sequenceId != other._sequenceId && 
> +                (this._sequenceId == null || 
> !this._sequenceId.equals(other._sequenceId)))
> +            {
> +                return false;
> +            }
> +            return true;
> +        }
> +
> +        @Override
> +        public int hashCode()
> +        {
> +            int hash = 7;
> +            hash = 83 * hash + (this._viewId != null ? this._viewId.hashCode() 
> : 0);
> +            hash = 83 * hash + (this._sequenceId != null ? 
> this._sequenceId.hashCode() : 0);
> +            return hash;
> +        }
> +    }
> +    
>      //------------------------------------- METHOD FROM StateCache 
> ------------------------------------------------
> 
>      @Override
> @@ -858,12 +1034,12 @@ class ServerSideStateCacheImpl extends S
>          }
>          //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);
>      }
> 
> @@ -886,7 +1062,7 @@ class ServerSideStateCacheImpl extends S
>      {
>          return 
> getKeyFactory(facesContext).encode(getNextViewSequence(facesContext));
>      }
> -
> +    
>      @Override
>      public boolean isWriteStateAfterRenderViewRequired(FacesContext 
> facesContext)
>      {
> @@ -894,7 +1070,7 @@ class ServerSideStateCacheImpl extends S
>      }
> 
>      //------------------------------------- Custom methods 
> -----------------------------------------------------
> -
> +    
>      private boolean isUseFlashScopePurgeViewsInSession(ExternalContext 
> externalContext)
>      {
>          if (_useFlashScopePurgeViewsInSession == null)
> @@ -904,29 +1080,372 @@ class ServerSideStateCacheImpl extends S
>          }
>          return _useFlashScopePurgeViewsInSession;
>      }
> -
> +    
>      private Integer getNumberOfSequentialViewsInSession(ExternalContext 
> externalContext)
>      {
>          if (!_numberOfSequentialViewsInSessionSet)
>          {
>              _numberOfSequentialViewsInSession = 
> WebConfigParamUtils.getIntegerInitParameter(
> -                    externalContext,
> +                    externalContext, 
>                      NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
>              _numberOfSequentialViewsInSessionSet = true;
>          }
>          return _numberOfSequentialViewsInSession;
>      }
> -
> +    
>      protected KeyFactory getKeyFactory(FacesContext facesContext)
>      {
>          //return keyFactory;
>          return sessionViewStorageFactory.getKeyFactory();
>      }
> -
> +    
>      protected SessionViewStorageFactory getSessionViewStorageFactory()
>      {
>          return sessionViewStorageFactory;
>      }
> +            
> 
> +    protected abstract static class KeyFactory<K, V>
> +    {
> +        
> +        /**
> +         * Generates a unique key per session 
> +         * 
> +         * @param facesContext
> +         * @return 
> +         */
> +        public abstract K generateKey(FacesContext facesContext);
> +        
> +        /**
> +         * Encode a Key into a value that will be used as view state session 
> token
> +         * 
> +         * @param key
> +         * @return 
> +         */
> +        public abstract V encode(K key);
> 
> +        /**
> +         * Decode a view state session token into a key
> +         * 
> +         * @param value
> +         * @return 
> +         */
> +        public abstract K decode(V value);
> +
> +    }
> +
> +    private static class CounterKeyFactory extends KeyFactory<Integer, 
> String>
> +    {
> +        /**
> +         * Take the counter from session scope and increment
> +         * 
> +         * @param facesContext
> +         * @return 
> +         */
> +        @Override
> +        public Integer generateKey(FacesContext facesContext)
> +        {
> +            ExternalContext externalContext = 
> facesContext.getExternalContext();
> +            Object sessionObj = externalContext.getSession(true);
> +            Integer sequence = null;
> +            synchronized(sessionObj) // synchronized to increase sequence if 
> multiple requests
> +                                    // are handled at the same time for the 
> session
> +            {
> +                Map<String, Object> map = 
> externalContext.getSessionMap();
> +                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);
> +            }
> +            return sequence;
> +        }
> +        
> +        public String encode(Integer sequence)
> +        {
> +            return Integer.toString(sequence, Character.MAX_RADIX);
> +        }
> +                
> +        public Integer decode(String serverStateId)
> +        {
> +             return Integer.valueOf((String) serverStateId, 
> Character.MAX_RADIX);
> +        }
> +    }
> +    
> +    /**
> +     * This factory generate a key composed by a counter and a random number. 
> The
> +     * counter ensures uniqueness, and the random number prevents guess the 
> next
> +     * session token.
> +     */
> +    private static class SecureRandomKeyFactory extends KeyFactory<byte[], 
> String>
> +    {
> +        private final SessionIdGenerator sessionIdGenerator;
> +        private final int length;
> +
> +        public SecureRandomKeyFactory(FacesContext facesContext)
> +        {
> +            length = 
> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
> +                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM, 
> +                    
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
> +            sessionIdGenerator = new SessionIdGenerator();
> +            sessionIdGenerator.setSessionIdLength(length);
> +            String secureRandomClass = 
> WebConfigParamUtils.getStringInitParameter(
> +                    facesContext.getExternalContext(),
> +                    
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_CLASS_PARAM);
> +            if (secureRandomClass != null)
> +            {
> +                sessionIdGenerator.setSecureRandomClass(secureRandomClass);
> +            }
> +            String secureRandomProvider = 
> WebConfigParamUtils.getStringInitParameter(
> +                    facesContext.getExternalContext(),
> +                    
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_PROVIDER_PARAM);
> +            if (secureRandomProvider != null)
> +            {
> +                
> sessionIdGenerator.setSecureRandomProvider(secureRandomProvider);
> +            }
> +            String secureRandomAlgorithm = 
> WebConfigParamUtils.getStringInitParameter(
> +                    facesContext.getExternalContext(), 
> +                    
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_SECURE_RANDOM_ALGORITM_PARAM);
> +            if (secureRandomAlgorithm != null)
> +            {
> +                
> sessionIdGenerator.setSecureRandomAlgorithm(secureRandomAlgorithm);
> +            }
> +        }
> +        
> +        public Integer generateCounterKey(FacesContext facesContext)
> +        {
> +            ExternalContext externalContext = 
> facesContext.getExternalContext();
> +            Object sessionObj = externalContext.getSession(true);
> +            Integer sequence = null;
> +            synchronized(sessionObj) // synchronized to increase sequence if 
> multiple requests
> +                                    // are handled at the same time for the 
> session
> +            {
> +                Map<String, Object> map = 
> externalContext.getSessionMap();
> +                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);
> +            }
> +            return sequence;
> +        }
> +
> +        @Override
> +        public byte[] generateKey(FacesContext facesContext)
> +        {
> +            byte[] array = new byte[length];
> +            byte[] key = new byte[length+4];
> +            
> +            sessionIdGenerator.getRandomBytes(array);
> +            for (int i = 0; i < array.length; i++)
> +            {
> +                key[i] = array[i];
> +            }
> +            int value = generateCounterKey(facesContext);
> +            key[array.length] =  (byte) (value >>> 24);
> +            key[array.length+1] =  (byte) (value >>> 16);
> +            key[array.length+2] =  (byte) (value >>> 8);
> +            key[array.length+3] =  (byte) (value);
> +            
> +            return key;
> +        }
> +
> +        @Override
> +        public String encode(byte[] key)
> +        {
> +            return new String(Hex.encodeHex(key));
> +        }
> +        
> +        @Override
> +        public byte[] decode(String value)
> +        {
> +            try
> +            {
> +                return Hex.decodeHex(value.toCharArray());
> +            }
> +            catch (DecoderException ex)
> +            {
> +                // Cannot decode, ignore silently, later it will be handled as
> +                // ViewExpiredException
> +            }
> +            return null;
> +        }
> +    }
> +    
> +    private static class RandomKeyFactory extends KeyFactory<byte[], 
> String>
> +    {
> +        private final Random random;
> +        private final int length;
> +        
> +        public RandomKeyFactory(FacesContext facesContext)
> +        {
> +            length = 
> WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
> +                    RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM, 
> +                    
> RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_LENGTH_PARAM_DEFAULT);
> +            random = new Random(((int)System.nanoTime())+this.hashCode());
> +        }
> +        
> +        public Integer generateCounterKey(FacesContext facesContext)
> +        {
> +            ExternalContext externalContext = 
> facesContext.getExternalContext();
> +            Object sessionObj = externalContext.getSession(true);
> +            Integer sequence = null;
> +            synchronized(sessionObj) // synchronized to increase sequence if 
> multiple requests
> +                                    // are handled at the same time for the 
> session
> +            {
> +                Map<String, Object> map = 
> externalContext.getSessionMap();
> +                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);
> +            }
> +            return sequence;
> +        }
> +
> +        @Override
> +        public byte[] generateKey(FacesContext facesContext)
> +        {
> +            byte[] array = new byte[length];
> +            byte[] key = new byte[length+4];
> +            
> +            //sessionIdGenerator.getRandomBytes(array);
> +            random.nextBytes(array);
> +            for (int i = 0; i < array.length; i++)
> +            {
> +                key[i] = array[i];
> +            }
> +            int value = generateCounterKey(facesContext);
> +            key[array.length] =  (byte) (value >>> 24);
> +            key[array.length+1] =  (byte) (value >>> 16);
> +            key[array.length+2] =  (byte) (value >>> 8);
> +            key[array.length+3] =  (byte) (value);
> +
> +            return key;
> +        }
> +
> +        @Override
> +        public String encode(byte[] key)
> +        {
> +            return new String(Hex.encodeHex(key));
> +        }
> +        
> +        @Override
> +        public byte[] decode(String value)
> +        {
> +            try
> +            {
> +                return Hex.decodeHex(value.toCharArray());
> +            }
> +            catch (DecoderException ex)
> +            {
> +                // Cannot decode, ignore silently, later it will be handled as
> +                // ViewExpiredException
> +            }
> +            return null;
> +        }
> +    }
> +    
> +    /**
> +     * 
> +     * @param <T>
> +     * @param <K>
> +     * @param <V> 
> +     */
> +    protected abstract static class SessionViewStorageFactory <T extends 
> KeyFactory<K,V>, K, V >
> +    {
> +        private KeyFactory<K, V> keyFactory;
> +        
> +        public SessionViewStorageFactory(KeyFactory<K, V> keyFactory)
> +        {
> +            this.keyFactory = keyFactory;
> +        }
> +        
> +        public KeyFactory<K, V> getKeyFactory()
> +        {
> +            return keyFactory;
> +        }
> +        
> +        public abstract SerializedViewCollection 
> createSerializedViewCollection(
> +                FacesContext context);
> +        
> +        public abstract SerializedViewKey createSerializedViewKey(
> +                FacesContext facesContext, String viewId, K key);
> +        
> +    }
> +    
> +    private static class CounterSessionViewStorageFactory 
> +        extends SessionViewStorageFactory <KeyFactory 
> <Integer,String>, Integer, String>
> +    {
> +        public CounterSessionViewStorageFactory(KeyFactory<Integer, 
> String> keyFactory)
> +        {
> +            super(keyFactory);
> +        }
> +
> +        @Override
> +        public SerializedViewCollection createSerializedViewCollection(
> +                FacesContext context)
> +        {
> +            return new SerializedViewCollection();
> +        }
> +
> +        @Override
> +        public SerializedViewKey createSerializedViewKey(
> +                FacesContext context, String viewId, Integer key)
> +        {
> +            if (context.isProjectStage(ProjectStage.Production))
> +            {
> +                return new IntIntSerializedViewKey(viewId.hashCode(), key);
> +            }
> +            else
> +            {
> +                return new ReferenceSerializedViewKey(viewId, key);
> +            }
> +        }
> +    }
> +    
> +    private static class RandomSessionViewStorageFactory
> +        extends SessionViewStorageFactory <KeyFactory <byte[],String>, 
> byte[], String>
> +    {
> +        public RandomSessionViewStorageFactory(KeyFactory<byte[], String> 
> keyFactory)
> +        {
> +            super(keyFactory);
> +        }
> +
> +        @Override
> +        public SerializedViewCollection createSerializedViewCollection(
> +                FacesContext context)
> +        {
> +            return new SerializedViewCollection();
> +        }
> +
> +        @Override
> +        public SerializedViewKey createSerializedViewKey(
> +                FacesContext context, String viewId, byte[] key)
> +        {
> +            if (context.isProjectStage(ProjectStage.Production))
> +            {
> +                return new IntByteArraySerializedViewKey(viewId.hashCode(), 
> key);
> +            }
> +            else
> +            {
> +                return new ReferenceSerializedViewKey(viewId, key);
> +            }
> +        }
> +    }
> }
> 

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Leonardo Uribe <lu...@gmail.com>.
2012/11/14 Mike Kienenberger <mk...@gmail.com>:
> Guys,
>
> In my opinion, any time someone feels the need to revert SOMEONE
> ELSE's code without that person's consent, the first step must be to
> have a public discussion on the topic, unless it is an obvious
> immediate security bug.
>
> We shouldn't be seeing revert wars, then a discussion.
>

+1 for discuss the concrete topic in public in deep, from a technical
perspective, before do any change in the code. I'll explain the problem in
deep in another mail, so people can get the idea about what we are
discussing about.

>
> On Wed, Nov 14, 2012 at 4:23 PM,  <lu...@apache.org> wrote:
>> Author: lu4242
>> Date: Wed Nov 14 21:23:35 2012
>> New Revision: 1409414
>>
>> URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
>> Log:
>> MYFACES-3638 revert commit 1408993 to include later solution without refactoring.

Re: svn commit: r1409414 - in /myfaces/core/trunk/impl: ./ src/main/java/org/apache/myfaces/renderkit/

Posted by Mike Kienenberger <mk...@gmail.com>.
Guys,

In my opinion, any time someone feels the need to revert SOMEONE
ELSE's code without that person's consent, the first step must be to
have a public discussion on the topic, unless it is an obvious
immediate security bug.

We shouldn't be seeing revert wars, then a discussion.


On Wed, Nov 14, 2012 at 4:23 PM,  <lu...@apache.org> wrote:
> Author: lu4242
> Date: Wed Nov 14 21:23:35 2012
> New Revision: 1409414
>
> URL: http://svn.apache.org/viewvc?rev=1409414&view=rev
> Log:
> MYFACES-3638 revert commit 1408993 to include later solution without refactoring.