You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by gc...@apache.org on 2010/03/18 23:22:01 UTC

svn commit: r925024 - in /myfaces/trinidad/branches/1.2.12.2-branch: trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/ trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/ trinidad-impl/src/main/java/org/apache/my...

Author: gcrawford
Date: Thu Mar 18 22:22:01 2010
New Revision: 925024

URL: http://svn.apache.org/viewvc?rev=925024&view=rev
Log:
TRINIDAD-1747 zip page state to reduce live memory

Added:
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ObjectInputStreamResolveClass.java
Modified:
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
    myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/CoreResponseStateManager.java

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts?rev=925024&r1=925023&r2=925024&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts Thu Mar 18 22:22:01 2010
@@ -453,4 +453,11 @@
 <!-- COMPARETO_TYPE_MISMATCH -->
 <resource key="COMPARETO_TYPE_MISMATCH">The type for "{0}" prevents it from being compared to "{1}".</resource>
 
+<!-- ZIP_STATE_FAILED -->
+<resource key="ZIP_STATE_FAILED">Failed to zip the page state.</resource>
+
+<!-- UNZIP_STATE_FAILED -->
+<resource key="UNZIP_STATE_FAILED">Failed to unzip the page state.</resource>
+
+
 </resources>

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java?rev=925024&r1=925023&r2=925024&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java Thu Mar 18 22:22:01 2010
@@ -6,9 +6,9 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,14 +18,24 @@
  */
 package org.apache.myfaces.trinidadinternal.application;
 
+import com.sun.facelets.FaceletViewHandler;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.Serializable;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
 
 import javax.faces.FactoryFinder;
 import javax.faces.application.StateManager;
@@ -38,23 +48,20 @@ import javax.faces.render.RenderKit;
 import javax.faces.render.RenderKitFactory;
 import javax.faces.render.ResponseStateManager;
 
+import org.apache.myfaces.trinidad.bean.util.StateUtils;
 import org.apache.myfaces.trinidad.component.UIXComponentBase;
 import org.apache.myfaces.trinidad.context.RequestContext;
+import org.apache.myfaces.trinidad.context.Window;
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
 import org.apache.myfaces.trinidad.util.ExternalContextUtils;
+import org.apache.myfaces.trinidad.util.TransientHolder;
+import org.apache.myfaces.trinidadinternal.context.RequestContextImpl;
+import org.apache.myfaces.trinidadinternal.context.TrinidadPhaseListener;
 import org.apache.myfaces.trinidadinternal.util.LRUCache;
+import org.apache.myfaces.trinidadinternal.util.ObjectInputStreamResolveClass;
 import org.apache.myfaces.trinidadinternal.util.SubKeyMap;
 import org.apache.myfaces.trinidadinternal.util.TokenCache;
 
-import com.sun.facelets.FaceletViewHandler;
-
-import java.io.ByteArrayOutputStream;
-import java.io.ObjectOutputStream;
-
-import org.apache.myfaces.trinidad.bean.util.StateUtils;
-import org.apache.myfaces.trinidad.context.Window;
-import org.apache.myfaces.trinidadinternal.context.RequestContextImpl;
-import org.apache.myfaces.trinidadinternal.context.TrinidadPhaseListener;
 
 /**
  * StateManager that handles a hybrid client/server strategy:  a
@@ -114,6 +121,15 @@ public class StateManagerImpl extends St
     "org.apache.myfaces.trinidad.CLIENT_STATE_MAX_TOKENS";
 
   /**
+     * Servlet context initialization parameter used by
+     * StateManagerImpl to decide whether to zip state.
+     * Valid values are true and false
+     */
+    static public final String COMPRESS_VIEW_STATE_PARAM_NAME =
+      "org.apache.myfaces.trinidadinternal.COMPRESS_VIEW_STATE";
+
+
+  /**
    * Value indicating that only a simple token will be stored
    * on the client.
    */
@@ -130,7 +146,7 @@ public class StateManagerImpl extends St
   {
     _delegate = delegate;
   }
-  
+
   @Override
   protected StateManager getWrapped()
   {
@@ -142,13 +158,13 @@ public class StateManagerImpl extends St
   public Object saveView(FacesContext context)
   {
     assert(context != null);
-    
+
     if(isSavingStateInClient(context))
     {
       SerializedView view = _saveSerializedView(context);
       return new Object[]{view.getStructure(), view.getState()};
     }
-    
+
     return super.saveView(context);
   }
 
@@ -156,12 +172,12 @@ public class StateManagerImpl extends St
   public SerializedView saveSerializedView(FacesContext context)
   {
     assert(context != null);
-    
+
     if(isSavingStateInClient(context))
     {
       return _saveSerializedView(context);
     }
-    
+
     return _delegate.saveSerializedView(context);
   }
 
@@ -177,7 +193,7 @@ public class StateManagerImpl extends St
     Object state = component.processSaveState(context);
     return new PageState(context, structure, state, null);
   }
-  
+
   /**
    * Take an object created by saveComponentTree()
    * and instantiate it as a UIComponent.
@@ -253,7 +269,7 @@ public class StateManagerImpl extends St
       root.processRestoreState(context, state);
 
     return root;
-  }  
+  }
 
   @SuppressWarnings({"unchecked", "deprecation"})
   private SerializedView _saveSerializedView(FacesContext context)
@@ -314,10 +330,10 @@ public class StateManagerImpl extends St
         Map<String, Object> sessionMap = extContext.getSessionMap();
 
         RequestContext trinContext = RequestContext.getCurrentInstance();
-        
+
         // get view cache key with "." separator suffix to separate the SubKeyMap keys
         String subkey = _getViewCacheKey(extContext, trinContext, _SUBKEY_SEPARATOR);
-        
+
         Map<String, PageState> stateMap = new SubKeyMap<PageState>(sessionMap, subkey);
 
         // Sadly, we can't save just a SerializedView, because we should
@@ -345,7 +361,7 @@ public class StateManagerImpl extends St
 
           sessionMap.put(activePageStateKey, pageState);
         }
-        
+
         String requestToken = _getRequestTokenForResponse(context);
         // If we have a cached token that we want to reuse,
         // and that token hasn't disappeared from the cache already
@@ -378,7 +394,7 @@ public class StateManagerImpl extends St
       {
         // use null viewRoot since this state is shared across users:
         PageState applicationState = new PageState(context, structure, state, null);
-        
+
         // If we need to, stash the state off in our cache
         if (!dontSave)
         {
@@ -399,7 +415,7 @@ public class StateManagerImpl extends St
       // Create a "tokenView" which abuses SerializedView to store
       // our token only
       view = new SerializedView(token, null);
-      
+
       // And store the token for this request
       extContext.getRequestMap().put(_REQUEST_STATE_TOKEN_KEY, token);
     }
@@ -425,9 +441,9 @@ public class StateManagerImpl extends St
   {
     context.getExternalContext().getRequestMap().put(
             _PINNED_STATE_TOKEN_KEY, stateToken);
-    
+
   }
-  
+
   /**
    * @return the state token for the current request
    */
@@ -436,24 +452,24 @@ public class StateManagerImpl extends St
     return (String) context.getExternalContext().getRequestMap().get(
             _REQUEST_STATE_TOKEN_KEY);
   }
-  
-  
+
+
   /**
    * Mark the the incoming request token should be used for the response
    */
   @SuppressWarnings("unchecked")
   static public void reuseRequestTokenForResponse(ExternalContext ec)
   {
-    ec.getRequestMap().put(_REUSE_REQUEST_TOKEN_FOR_RESPONSE_KEY, Boolean.TRUE);    
+    ec.getRequestMap().put(_REUSE_REQUEST_TOKEN_FOR_RESPONSE_KEY, Boolean.TRUE);
   }
-  
+
   /**
    * Clears the flag indicating that the old request token should be used for the response.
    */
   @SuppressWarnings("unchecked")
   static public void clearReuseRequestTokenForResponse(ExternalContext ec)
   {
-    ec.getRequestMap().remove(_REUSE_REQUEST_TOKEN_FOR_RESPONSE_KEY);    
+    ec.getRequestMap().remove(_REUSE_REQUEST_TOKEN_FOR_RESPONSE_KEY);
   }
 
   /**
@@ -489,8 +505,8 @@ public class StateManagerImpl extends St
 
     return (String) token;
   }
-    
-  
+
+
   @Override @SuppressWarnings("deprecation")
   public void writeState(FacesContext context,
                          SerializedView state) throws IOException
@@ -504,8 +520,8 @@ public class StateManagerImpl extends St
                                 String renderKitId)
   {
     final ExternalContext extContext = context.getExternalContext();
-    
-    // If we're being asked to execute a "return" event from, say, a dialog, always 
+
+    // If we're being asked to execute a "return" event from, say, a dialog, always
     // restore the "launch view", which was set over in the TrinidadFilter.
     UIViewRoot launchView = (UIViewRoot)
                             extContext.getRequestMap().remove(RequestContextImpl.LAUNCH_VIEW);
@@ -514,7 +530,7 @@ public class StateManagerImpl extends St
       TrinidadPhaseListener.markPostback(context);
       return launchView;
     }
-    
+
     if (!isSavingStateInClient(context))
       return _delegate.restoreView(context, viewId, renderKitId);
 
@@ -559,10 +575,10 @@ public class StateManagerImpl extends St
             if (viewState != null)
               perSessionCache.put(viewId, viewState);
           }
-          
+
           // If the view was found in the application cache then we
           // know it would be unsafe to use its locale for this session.
-          // Same conclusion, however, even if found in the per-session 
+          // Same conclusion, however, even if found in the per-session
           // cache, since the latter is just a mirror of the former.
           recalculateLocale = true;
         }
@@ -573,7 +589,7 @@ public class StateManagerImpl extends St
         String subkey = _getViewCacheKey(extContext,
                                          RequestContext.getCurrentInstance(),
                                          _SUBKEY_SEPARATOR);
-        
+
         Map<String, PageState> stateMap = new SubKeyMap<PageState>(
                          extContext.getSessionMap(),
                          subkey);
@@ -649,7 +665,7 @@ public class StateManagerImpl extends St
 
         if (state != null)
           root.processRestoreState(context, state);
-        
+
         if (recalculateLocale)
         {
           // Ensure that locale gets re-calculated when next fetched.
@@ -716,7 +732,7 @@ public class StateManagerImpl extends St
   private TokenCache _getViewCache(FacesContext context)
   {
     ExternalContext extContext = context.getExternalContext();
-    
+
     return TokenCache.getTokenCacheFromSession(context,
                                                _getViewCacheKey(extContext,
                                                                 RequestContext.getCurrentInstance(),
@@ -725,7 +741,7 @@ public class StateManagerImpl extends St
                                                _getCacheSize(extContext));
   }
 
-  
+
 
   /**
    * Returns a key suitable for finding the per-window active page state key
@@ -739,7 +755,7 @@ public class StateManagerImpl extends St
   {
     return _getPerWindowCacheKey(extContext, trinContext, _ACTIVE_PAGE_STATE_SESSION_KEY, null);
   }
-  
+
   /**
    * Returns a key suitable for finding the per-window cache key
    * @param extContext
@@ -754,7 +770,7 @@ public class StateManagerImpl extends St
   {
     return _getPerWindowCacheKey(extContext, trinContext, _VIEW_CACHE_KEY, suffix);
   }
-  
+
   /**
    * Returns a key of the form <prefix>.<windowid><suffix> if a window and a suffix are available
    *                           <prefix>.<window> if just a window is available
@@ -772,18 +788,18 @@ public class StateManagerImpl extends St
     Character suffix)
   {
     Window currWindow = trinContext.getWindowManager().getCurrentWindow(eContext);
-    
+
     // if we have a current window or a suffix, we need a StringBuilder to calculate the cache key
     if ((currWindow != null) || (suffix != null))
     {
       // get the window id and the extra size neeeded to store it and its separator
       String windowId;
       int windowPartSize;
-    
+
       if (currWindow != null)
       {
         windowId = currWindow.getId();
-        
+
         // add 1 for separator
         windowPartSize = windowId.length() + 1;
       }
@@ -792,28 +808,28 @@ public class StateManagerImpl extends St
         windowId = null;
         windowPartSize = 0;
       }
-      
+
       int builderSize =  prefix.length() + windowPartSize;
-      
+
       // add extra space for the suffix Character
       if (suffix != null)
         builderSize += 1;
-      
+
       // add the constant part to the StringBuilder
       StringBuilder keyBuilder = new StringBuilder(builderSize);
       keyBuilder.append(prefix);
-      
+
       // add the windowId and its separator
       if (currWindow != null)
       {
         keyBuilder.append('.');
         keyBuilder.append(windowId);
       }
-      
+
       // add the suffix if any
       if (suffix != null)
         keyBuilder.append(suffix);
-      
+
       return keyBuilder.toString();
     }
     else
@@ -880,7 +896,7 @@ public class StateManagerImpl extends St
       return cache;
     }
   }
-  
+
   @SuppressWarnings("unchecked")
   static private Map<String, PageState> _getPerSessionApplicationViewCache(FacesContext context)
   {
@@ -943,7 +959,7 @@ public class StateManagerImpl extends St
       }
       if (Boolean.TRUE.equals(_useApplicationViewCache))
       {
-         _LOG.severe("USE_APPLICATION_VIEW_CACHE_UNSUPPORTED");        
+         _LOG.severe("USE_APPLICATION_VIEW_CACHE_UNSUPPORTED");
       }
       return _useApplicationViewCache.booleanValue();
     }
@@ -1016,18 +1032,18 @@ public class StateManagerImpl extends St
       // Nope, guess it's a facet
       // 2006-08-02: -= Simon Lessard
       //             Not 1.5 structure and inefficient loop
-      //             values() is more efficient as you don't have 
+      //             values() is more efficient as you don't have
       //             to do a second lookup for the value.
       Map<String, UIComponent> facets = parent.getFacets();
-      for(Iterator<UIComponent> facetIter = facets.values().iterator(); 
+      for(Iterator<UIComponent> facetIter = facets.values().iterator();
           facetIter.hasNext();)
       {
         if(facetIter.next() == kid)
         {
           facetIter.remove();
           // FIXME: -= Simon Lessard
-          //        Is that continue need to labeled to go all the way up to 
-          //        the first while? Currently it won't cause any problem, but 
+          //        Is that continue need to labeled to go all the way up to
+          //        the first while? Currently it won't cause any problem, but
           //        it's a performance loss.
           continue;
         }
@@ -1083,11 +1099,11 @@ public class StateManagerImpl extends St
     {
       if (viewRoot == null)
         throw new NullPointerException();
-      
+
       _viewRoot = viewRoot;
       _viewRootState = viewRoot.saveState(context);
     }
-    
+
     public UIViewRoot getViewRoot()
     {
       return _viewRoot;
@@ -1097,7 +1113,7 @@ public class StateManagerImpl extends St
     {
       return _viewRootState;
     }
-   
+
     private final UIViewRoot _viewRoot;
     private final Object _viewRootState;
   }
@@ -1106,8 +1122,8 @@ public class StateManagerImpl extends St
   {
     private static final long serialVersionUID = 1L;
 
-    private final Object _structure, _state;
-    
+    private Object _structure, _state;
+
     // use transient since UIViewRoots are not Serializable.
     private transient ViewRootState _cachedState;
 
@@ -1115,22 +1131,33 @@ public class StateManagerImpl extends St
     {
       _structure = structure;
       _state = state;
-      
-      // if component tree serialization checking is on (in order to validate
-      // fail over support, attempt to Serialize all of the component state
-      //  immediately
-      if (StateUtils.checkComponentTreeStateSerialization(fc))
+
+      boolean zipState = _zipState(fc);
+
+      if (zipState || StateUtils.checkComponentTreeStateSerialization(fc))
       {
-        try
+
+        if (zipState)
         {
-          new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(state);
+          // zip the page state. This will also catch any serialization problems.
+          _zipToBytes(state, structure);
         }
-        catch (IOException e)
-        {          
-          throw new RuntimeException(_LOG.getMessage("COMPONENT_TREE_SERIALIZATION_FAILED"), e);
+        else
+        {
+          // if component tree serialization checking is on (in order to validate
+          // fail over support, attempt to Serialize all of the component state
+          //  immediately
+          try
+          {
+            new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(state);
+          }
+          catch (IOException e)
+          {
+            throw new RuntimeException(_LOG.getMessage("COMPONENT_TREE_SERIALIZATION_FAILED"), e);
+          }
         }
       }
-                  
+
       // we need this state, as we are going to recreate the UIViewRoot later. see
       // the popRoot() method:
       _cachedState = (root != null)
@@ -1140,11 +1167,21 @@ public class StateManagerImpl extends St
 
     public Object getStructure()
     {
+      if (_zipState(FacesContext.getCurrentInstance()))
+      {
+        return _unzipBytes((byte[])_structure);
+      }
+
       return _structure;
     }
 
     public Object getState()
     {
+      if (_zipState(FacesContext.getCurrentInstance()))
+      {
+        return _unzipBytes((byte[])_state);
+      }
+
       return _state;
     }
 
@@ -1155,7 +1192,7 @@ public class StateManagerImpl extends St
         _cachedState = null;
       }
     }
-    
+
     @SuppressWarnings("unchecked")
     public UIViewRoot popRoot(FacesContext fc)
     {
@@ -1176,7 +1213,7 @@ public class StateManagerImpl extends St
           _cachedState = null;
         }
       }
-      
+
       if (root != null)
       {
         // If an error happens during updateModel, JSF 1.1 does not
@@ -1185,11 +1222,11 @@ public class StateManagerImpl extends St
         // so to clear the events, we create a new UIViewRoot.
         // must get the UIViewRoot from the application so that
         // we pick up any custom ViewRoot defined in faces-config.xml:
-        UIViewRoot newRoot = (UIViewRoot) 
+        UIViewRoot newRoot = (UIViewRoot)
           fc.getApplication().createComponent(UIViewRoot.COMPONENT_TYPE);
-        
+
         //This code handles automatic namespacing in a JSR-301 environment
-        if(ExternalContextUtils.isPortlet(fc.getExternalContext())) 
+        if(ExternalContextUtils.isPortlet(fc.getExternalContext()))
         {
           //IMPORTANT: To avoid introducing a runtime dependency on the bridge,
           //this method should only be executed when we have a portlet
@@ -1200,7 +1237,7 @@ public class StateManagerImpl extends St
           newRoot = PortletUtils.getPortletViewRoot(newRoot);
         }
 
-        
+
         // must call restoreState so that we setup attributes, listeners,
         // uniqueIds, etc ...
         newRoot.restoreState(fc, viewRootState);
@@ -1216,9 +1253,170 @@ public class StateManagerImpl extends St
         newRoot.getChildren().addAll(temp);
         return newRoot;
       }
-      
+
       return null;
-    }    
+    }
+
+    private boolean _zipState(FacesContext fc)
+    {
+      // default is false
+      Object zipStateObject = 
+                           fc.getExternalContext().getInitParameter(COMPRESS_VIEW_STATE_PARAM_NAME);
+
+      if (zipStateObject == null)
+        return false;
+
+      return zipStateObject.toString().equalsIgnoreCase("true");
+    }
+
+    private Object _unzipBytes(byte[] zippedBytes)
+    {
+      Inflater decompressor = null;
+      ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
+      Map<String,Object> sessionMap  = externalContext.getSessionMap();
+        
+      try
+      {
+        //Get inflater from session cope
+        TransientHolder<Inflater> th = 
+                              (TransientHolder<Inflater>)sessionMap.remove("PAGE_STATE_INFLATER");
+        
+        if (th != null)
+        {
+          decompressor = th.getValue();
+        }
+        
+        if(decompressor == null) 
+        {
+          decompressor = new Inflater();
+        }
+        
+		    decompressor.setInput(zippedBytes);
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(zippedBytes.length);
+        byte[] buf = new byte[zippedBytes.length*5];
+
+        while (!decompressor.finished())
+        {
+	        try
+		      {
+		        int count = decompressor.inflate(buf);
+		        bos.write(buf, 0, count);
+		      }
+		      catch (DataFormatException e)
+		      {
+            throw new RuntimeException(_LOG.getMessage("UNZIP_STATE_FAILED"), e); 
+          }
+		    }
+
+        ByteArrayInputStream baos = new ByteArrayInputStream(bos.toByteArray());
+        ObjectInputStream ois = new ObjectInputStreamResolveClass(baos);
+        Object unzippedState = ois.readObject();
+        ois.close();
+        return unzippedState;
+      }
+      catch(ClassNotFoundException cnfe)
+      {
+        throw new RuntimeException(_LOG.getMessage("UNZIP_STATE_FAILED"), cnfe);
+      }
+      catch(IOException ioe)
+      {
+        throw new RuntimeException(_LOG.getMessage("UNZIP_STATE_FAILED"), ioe);
+      }
+      finally 
+      {
+        //Reset and put back
+        if(decompressor != null)
+        {
+          decompressor.reset();
+          TransientHolder<Inflater> th = TransientHolder.newTransientHolder(decompressor);
+          sessionMap.put("PAGE_STATE_INFLATER", th);
+        }
+      }
+    }
+
+    private void _zipToBytes(Object state, Object structure)
+    {
+      Deflater compresser = null;
+      ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
+      Map<String,Object> sessionMap  = externalContext.getSessionMap();
+      
+      try
+      {
+        //Get deflater from session cope
+        TransientHolder<Deflater> th = 
+                              (TransientHolder<Deflater>)sessionMap.remove("PAGE_STATE_DEFLATER");
+        
+        if (th != null)
+        {
+          compresser = th.getValue();
+        }
+        
+        if(compresser == null) 
+        {
+          compresser = new Deflater(Deflater.BEST_SPEED);
+        }
+        
+        //Serialize state
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+        
+        oos.writeObject(state);
+        oos.flush();
+        oos.close();
+
+        byte[] ret =  baos.toByteArray();
+        compresser.setInput(ret);
+		    compresser.finish();
+
+        baos.reset();
+        byte[] buf = new byte[ret.length/5];
+
+        while (!compresser.finished())
+        {
+			    int count = compresser.deflate(buf);
+			    baos.write(buf, 0, count);
+		    }
+
+        _state = baos.toByteArray();
+        
+        //Serialize structure
+        baos.reset();
+        oos = new ObjectOutputStream(baos);
+        compresser.reset();
+        
+        oos.writeObject(structure);
+        oos.flush();
+        oos.close();
+        
+        ret =  baos.toByteArray();
+        compresser.setInput(ret);
+        compresser.finish();
+        
+        baos.reset();
+
+        while (!compresser.finished())
+        {
+          int count = compresser.deflate(buf);
+          baos.write(buf, 0, count);
+        }
+
+        _structure = baos.toByteArray();
+      }
+      catch (IOException e)
+      {
+        throw new RuntimeException(_LOG.getMessage("ZIP_STATE_FAILED"), e);
+      }
+      finally 
+      {
+        //Reset and put back
+        if(compresser != null)
+        {
+          compresser.reset();
+          TransientHolder<Deflater> th = TransientHolder.newTransientHolder(compresser);
+          sessionMap.put("PAGE_STATE_DEFLATER", th);
+        }
+      }
+    }
   }
 
   private final StateManager _delegate;
@@ -1227,11 +1425,11 @@ public class StateManagerImpl extends St
   private       Boolean      _structureGeneratedByTemplate;
 
   private static final Character _SUBKEY_SEPARATOR = new Character('.');
-  
+
   private static final int _DEFAULT_CACHE_SIZE = 15;
 
   private static final Object _APPLICATION_VIEW_CACHE_LOCK = new Object();
-  
+
   // base key used to identify the view cache.  The window name, if any, is appended to this
   private static final String _VIEW_CACHE_KEY =
     "org.apache.myfaces.trinidadinternal.application.VIEW_CACHE";

Modified: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/CoreResponseStateManager.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/CoreResponseStateManager.java?rev=925024&r1=925023&r2=925024&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/CoreResponseStateManager.java (original)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/CoreResponseStateManager.java Thu Mar 18 22:22:01 2010
@@ -46,6 +46,7 @@ import org.apache.myfaces.trinidad.loggi
 import org.apache.myfaces.trinidad.util.Base64InputStream;
 import org.apache.myfaces.trinidad.util.Base64OutputStream;
 import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
+import org.apache.myfaces.trinidadinternal.util.ObjectInputStreamResolveClass;
 
 /**
  * ResponseStateManager implementation for the Core RenderKit.
@@ -184,21 +185,7 @@ public class CoreResponseStateManager ex
         try
         {
           ObjectInputStream ois;
-          ois = new ObjectInputStream( new GZIPInputStream( b64_in,
-                                                            _BUFFER_SIZE ))
-            {
-              protected Class<?> resolveClass(ObjectStreamClass desc)
-                                       throws IOException,
-                                              ClassNotFoundException
-              {
-                // TRINIDAD-1062 It has been noticed that in OC4J and Weblogic that the
-                // classes being resolved are having problems by not finding
-                // them using the context class loader. Therefore, we are adding
-                // this work-around until the problem with these application
-                // servers can be better understood
-                return ClassLoaderUtils.loadClass(desc.getName());
-              }
-            };
+          ois = new ObjectInputStreamResolveClass( new GZIPInputStream( b64_in, _BUFFER_SIZE ));
 
           Object structure = ois.readObject();
           Object state = ois.readObject();

Added: myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ObjectInputStreamResolveClass.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ObjectInputStreamResolveClass.java?rev=925024&view=auto
==============================================================================
--- myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ObjectInputStreamResolveClass.java (added)
+++ myfaces/trinidad/branches/1.2.12.2-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ObjectInputStreamResolveClass.java Thu Mar 18 22:22:01 2010
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidadinternal.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+
+import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
+
+public class ObjectInputStreamResolveClass extends ObjectInputStream
+{
+  public ObjectInputStreamResolveClass()  throws IOException, SecurityException
+  {
+    super();
+  }
+
+  public ObjectInputStreamResolveClass(InputStream in) throws IOException 
+  {
+    super(in);
+  }
+  
+  protected Class<?> resolveClass(ObjectStreamClass desc)
+                           throws IOException,
+                                  ClassNotFoundException
+  {
+    // TRINIDAD-1062 It has been noticed that in OC4J and Weblogic that the
+    // classes being resolved are having problems by not finding
+    // them using the context class loader. Therefore, we are adding
+    // this work-around until the problem with these application
+    // servers can be better understood
+    return ClassLoaderUtils.loadClass(desc.getName());
+  }
+}