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:20:05 UTC
svn commit: r925023 - in /myfaces/trinidad/trunk:
trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
Author: gcrawford
Date: Thu Mar 18 22:20:05 2010
New Revision: 925023
URL: http://svn.apache.org/viewvc?rev=925023&view=rev
Log:
TRINIDAD-1747 zip page state to reduce live memory
Modified:
myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
Modified: myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts?rev=925023&r1=925022&r2=925023&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts Thu Mar 18 22:20:05 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/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java?rev=925023&r1=925022&r2=925023&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java Thu Mar 18 22:20:05 2010
@@ -19,8 +19,10 @@
package org.apache.myfaces.trinidadinternal.application;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
@@ -28,6 +30,9 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
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;
@@ -48,6 +53,7 @@ import org.apache.myfaces.trinidad.conte
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.SubKeyMap;
@@ -87,6 +93,14 @@ public class StateManagerImpl extends St
*/
static public final String CLIENT_STATE_MAX_TOKENS_PARAM_NAME =
"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
@@ -955,7 +969,7 @@ public class StateManagerImpl extends St
{
private static final long serialVersionUID = 1L;
- private final Object _viewState;
+ private Object _viewState;
// use transient since UIViewRoots are not Serializable.
private transient ViewRootState _cachedState;
@@ -963,19 +977,30 @@ public class StateManagerImpl extends St
public PageState(FacesContext fc, Object viewState, UIViewRoot root)
{
_viewState = viewState;
-
- // 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(viewState);
+ // zip the page state. This will also catch any serialization problems.
+ _zipToBytes(viewState);
}
- 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(viewState);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(_LOG.getMessage("COMPONENT_TREE_SERIALIZATION_FAILED"), e);
+ }
}
}
@@ -988,6 +1013,11 @@ public class StateManagerImpl extends St
public Object getViewState()
{
+ if (_zipState(FacesContext.getCurrentInstance()))
+ {
+ return _unzipBytes((byte[])_viewState);
+ }
+
return _viewState;
}
@@ -1062,6 +1092,146 @@ public class StateManagerImpl extends St
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 ObjectInputStream(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)
+ {
+ 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);
+ }
+
+ _viewState = 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);
+ }
+ }
+ }
}
// TODO - we used to delegate to the RI when the stateManagement method was server,