You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2011/05/14 03:05:41 UTC
svn commit: r1102936 - in /myfaces/core/branches/2.0.x/impl/src:
main/conf/META-INF/ main/java/org/apache/myfaces/application/
main/java/org/apache/myfaces/renderkit/
main/java/org/apache/myfaces/renderkit/html/
main/java/org/apache/myfaces/view/facele...
Author: lu4242
Date: Sat May 14 01:05:41 2011
New Revision: 1102936
URL: http://svn.apache.org/viewvc?rev=1102936&view=rev
Log:
MYFACES-3117 Current server state saving implementation prevents multi-window usage
Added:
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ClientSideStateCacheImpl.java
- copied, changed from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
- copied, changed from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheFactoryImpl.java
- copied, changed from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheUtils.java
myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ServerSideStateCacheTest.java
Removed:
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCacheImpl.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java
Modified:
myfaces/core/branches/2.0.x/impl/src/main/conf/META-INF/standard-faces-config-base.xml
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCache.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ViewHandlerImpl.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/MyfacesResponseStateManager.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/StateWriter.java
myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java
Modified: myfaces/core/branches/2.0.x/impl/src/main/conf/META-INF/standard-faces-config-base.xml
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/conf/META-INF/standard-faces-config-base.xml?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/conf/META-INF/standard-faces-config-base.xml (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/conf/META-INF/standard-faces-config-base.xml Sat May 14 01:05:41 2011
@@ -29,7 +29,7 @@
<application>
<action-listener>org.apache.myfaces.application.ActionListenerImpl</action-listener>
<view-handler>org.apache.myfaces.application.ViewHandlerImpl</view-handler>
- <state-manager>org.apache.myfaces.application.jsp.JspStateManagerImpl</state-manager>
+ <state-manager>org.apache.myfaces.application.StateManagerImpl</state-manager>
<navigation-handler>org.apache.myfaces.application.NavigationHandlerImpl</navigation-handler>
<resource-handler>org.apache.myfaces.application.ResourceHandlerImpl</resource-handler>
<!--
Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java Sat May 14 01:05:41 2011
@@ -18,25 +18,24 @@
*/
package org.apache.myfaces.application;
-import org.apache.commons.beanutils.BeanUtils;
-import org.apache.myfaces.application.jsp.JspStateManagerImpl;
-import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
-import org.apache.myfaces.config.RuntimeConfig;
-import org.apache.myfaces.config.element.Property;
-import org.apache.myfaces.config.element.ResourceBundle;
-import org.apache.myfaces.context.RequestViewContext;
-import org.apache.myfaces.el.PropertyResolverImpl;
-import org.apache.myfaces.el.VariableResolverToApplicationELResolverAdapter;
-import org.apache.myfaces.el.convert.MethodExpressionToMethodBinding;
-import org.apache.myfaces.el.convert.ValueBindingToValueExpression;
-import org.apache.myfaces.el.convert.ValueExpressionToValueBinding;
-import org.apache.myfaces.el.unified.ELResolverBuilder;
-import org.apache.myfaces.el.unified.ResolverBuilderForFaces;
-import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver;
-import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver.Scope;
-import org.apache.myfaces.lifecycle.LifecycleImpl;
-import org.apache.myfaces.shared_impl.util.ClassUtils;
-import org.apache.myfaces.view.facelets.el.ELText;
+import java.beans.BeanDescriptor;
+import java.beans.BeanInfo;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.el.CompositeELResolver;
import javax.el.ELContext;
@@ -86,24 +85,25 @@ import javax.faces.view.ViewDeclarationL
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
-import java.beans.BeanDescriptor;
-import java.beans.BeanInfo;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.MissingResourceException;
-import java.util.TimeZone;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+import org.apache.myfaces.config.RuntimeConfig;
+import org.apache.myfaces.config.element.Property;
+import org.apache.myfaces.config.element.ResourceBundle;
+import org.apache.myfaces.context.RequestViewContext;
+import org.apache.myfaces.el.PropertyResolverImpl;
+import org.apache.myfaces.el.VariableResolverToApplicationELResolverAdapter;
+import org.apache.myfaces.el.convert.MethodExpressionToMethodBinding;
+import org.apache.myfaces.el.convert.ValueBindingToValueExpression;
+import org.apache.myfaces.el.convert.ValueExpressionToValueBinding;
+import org.apache.myfaces.el.unified.ELResolverBuilder;
+import org.apache.myfaces.el.unified.ResolverBuilderForFaces;
+import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver;
+import org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver.Scope;
+import org.apache.myfaces.lifecycle.LifecycleImpl;
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.view.facelets.el.ELText;
/**
* DOCUMENT ME!
@@ -235,7 +235,7 @@ public class ApplicationImpl extends App
_navigationHandler = new NavigationHandlerImpl();
_actionListener = new ActionListenerImpl();
_defaultRenderKitId = "HTML_BASIC";
- _stateManager = new JspStateManagerImpl();
+ _stateManager = new StateManagerImpl();
_elContextListeners = new ArrayList<ELContextListener>();
_resourceHandler = new ResourceHandlerImpl();
_runtimeConfig = runtimeConfig;
Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCache.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCache.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCache.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateCache.java Sat May 14 01:05:41 2011
@@ -21,7 +21,8 @@ package org.apache.myfaces.application;
import javax.faces.context.FacesContext;
/**
- *
+ * This class provides and interface to separate the state caching operations (saving/restoring)
+ * from the renderkit specific stuff that HtmlResponseStateManager should do.
*
* @author Leonardo Uribe
*
@@ -38,6 +39,8 @@ public abstract class StateCache<K, V>
public abstract K saveSerializedView(FacesContext facesContext, V serializedView);
/**
+ * Get the state from the cache is server side state saving is used,
+ * or decode it from the passed viewState param if client side is used.
*
* @param facesContext
* @param viewId The viewId of the view to be restored
@@ -48,6 +51,8 @@ public abstract class StateCache<K, V>
public abstract V restoreSerializedView(FacesContext facesContext, String viewId, K viewState);
/**
+ * Calculate the token to be used if server side state saving, or encode the view and return the
+ * viewState that can be used by the underlying ResponseStateManager to write the state.
*
* @param facesContext
* @param state The state that will be used to derive the token returned.
@@ -55,5 +60,16 @@ public abstract class StateCache<K, V>
* ResponseStateManager.writeState or ResponseStateManager.getViewState to be
* output to the client.
*/
- //public abstract K encodeSerializedState(FacesContext facesContext, Object serializedView);
+ public abstract K encodeSerializedState(FacesContext facesContext, Object serializedView);
+
+ /**
+ * Indicates if the call to ResponseStateManager.writeState should be done after the view is fully rendered.
+ * Usually this is required for client side state saving, but it is not for server side state saving, because
+ * ResponseStateManager.writeState could render a just a marker and then StateManager.saveState could be called,
+ * preventing use an additional buffer.
+ *
+ * @param facesContext
+ * @return
+ */
+ public abstract boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext);
}
Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/StateManagerImpl.java Sat May 14 01:05:41 2011
@@ -38,6 +38,8 @@ import javax.faces.render.ResponseStateM
import javax.faces.view.StateManagementStrategy;
import javax.faces.view.ViewDeclarationLanguage;
+import org.apache.myfaces.renderkit.StateCacheUtils;
+
public class StateManagerImpl extends StateManager
{
private static final Logger log = Logger.getLogger(StateManagerImpl.class.getName());
@@ -140,7 +142,9 @@ public class StateManagerImpl extends St
@Override
public Object saveView(FacesContext facesContext)
{
+ Object serializedView = null;
UIViewRoot uiViewRoot = facesContext.getViewRoot();
+ ResponseStateManager responseStateManager = facesContext.getRenderKit().getResponseStateManager();
String viewId = uiViewRoot.getViewId();
ViewDeclarationLanguage vdl = facesContext.getApplication().
@@ -153,7 +157,16 @@ public class StateManagerImpl extends St
{
if (log.isLoggable(Level.FINEST)) log.finest("Calling saveView of StateManagementStrategy: "+sms.getClass().getName());
- return sms.saveView(facesContext);
+ serializedView = sms.saveView(facesContext);
+
+ // If MyfacesResponseStateManager is used, give the option to do
+ // additional operations for save the state if is necessary.
+ if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+ {
+ StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).saveState(facesContext, serializedView);
+ }
+
+ return serializedView;
}
}
@@ -175,7 +188,7 @@ public class StateManagerImpl extends St
ExternalContext externalContext = facesContext.getExternalContext();
// SerializedView already created before within this request?
- Object serializedView = externalContext.getRequestMap()
+ serializedView = externalContext.getRequestMap()
.get(SERIALIZED_VIEW_REQUEST_ATTR);
if (serializedView == null)
{
@@ -190,6 +203,13 @@ public class StateManagerImpl extends St
if (log.isLoggable(Level.FINEST)) log.finest("Processing saveSerializedView - new serialized view created");
}
+
+ // If MyfacesResponseStateManager is used, give the option to do
+ // additional operations for save the state if is necessary.
+ if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+ {
+ StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).saveState(facesContext, serializedView);
+ }
if (log.isLoggable(Level.FINEST)) log.finest("Exiting saveView");
@@ -284,32 +304,6 @@ public class StateManagerImpl extends St
}
- /*
- * NOTE: This is not required anymore, because all logic related to state storing or caching on session has
- * been moved to ResponseStateManager
- @Override
- public String getViewState(FacesContext facesContext)
- {
- UIViewRoot uiViewRoot = facesContext.getViewRoot();
- String viewId = uiViewRoot.getViewId();
- ViewDeclarationLanguage vdl = facesContext.getApplication().getViewHandler().getViewDeclarationLanguage(facesContext,viewId);
- if (vdl != null)
- {
- StateManagementStrategy sms = vdl.getStateManagementStrategy(facesContext, viewId);
-
- if (sms != null)
- {
- if (log.isLoggable(Level.FINEST)) log.finest("Calling saveView of StateManagementStrategy from getViewState: "+sms.getClass().getName());
-
- return facesContext.getRenderKit().getResponseStateManager().getViewState(facesContext, saveView(facesContext));
- }
- }
- Object[] savedState = (Object[]) saveView(facesContext);
-
- return facesContext.getRenderKit().getResponseStateManager().getViewState(facesContext, savedState);
-
- }*/
-
//helpers
protected RenderKitFactory getRenderKitFactory()
Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ViewHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ViewHandlerImpl.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ViewHandlerImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/application/ViewHandlerImpl.java Sat May 14 01:05:41 2011
@@ -45,7 +45,8 @@ import javax.faces.view.ViewDeclarationL
import javax.faces.view.ViewMetadata;
import javax.servlet.http.HttpServletResponse;
-import org.apache.myfaces.application.jsp.JspStateManagerImpl;
+import org.apache.myfaces.renderkit.MyfacesResponseStateManager;
+import org.apache.myfaces.renderkit.StateCacheUtils;
import org.apache.myfaces.shared_impl.application.DefaultViewHandlerSupport;
import org.apache.myfaces.shared_impl.application.InvalidViewIdException;
import org.apache.myfaces.shared_impl.application.ViewHandlerSupport;
@@ -286,10 +287,35 @@ public class ViewHandlerImpl extends Vie
if(context.getPartialViewContext().isAjaxRequest())
return;
- setWritingState(context);
+ ResponseStateManager responseStateManager = context.getRenderKit().getResponseStateManager();
+
+ setWritingState(context, responseStateManager);
StateManager stateManager = context.getApplication().getStateManager();
- if (stateManager.isSavingStateInClient(context))
+
+ // By the spec, it is necessary to use a writer to write FORM_STATE_MARKER,
+ // after the view is rendered, to preserve changes done on the component tree
+ // on rendering time. But if server side state saving is used, this is not
+ // really necessary, because a token could be used and after the view is
+ // rendered, a simple call to StateManager.saveState() could do the trick.
+ // The code below check if we are using MyFacesResponseStateManager and if
+ // that so, check if the current one support the trick.
+ if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+ {
+ if (StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).isWriteStateAfterRenderViewRequired(context))
+ {
+ // Only write state marker if javascript view state is disabled
+ ExternalContext extContext = context.getExternalContext();
+ if (!(JavascriptUtils.isJavascriptAllowed(extContext) && MyfacesConfig.getCurrentInstance(extContext).isViewStateJavascript())) {
+ context.getResponseWriter().write(FORM_STATE_MARKER);
+ }
+ }
+ else
+ {
+ stateManager.writeState(context, new Object[2]);
+ }
+ }
+ else
{
// Only write state marker if javascript view state is disabled
ExternalContext extContext = context.getExternalContext();
@@ -297,13 +323,9 @@ public class ViewHandlerImpl extends Vie
context.getResponseWriter().write(FORM_STATE_MARKER);
}
}
- else
- {
- stateManager.writeState(context, new Object[2]);
- }
}
- private void setWritingState(FacesContext context){
+ private void setWritingState(FacesContext context, ResponseStateManager rsm){
// Facelets specific hack:
// Tell the StateWriter that we're about to write state
StateWriter stateWriter = StateWriter.getCurrentInstance();
@@ -313,7 +335,25 @@ public class ViewHandlerImpl extends Vie
// be wasteful for pure server-side state managers where nothing
// is actually written into the output, but this cannot
// programatically be discovered
- stateWriter.writingState();
+ // -= Leonardo Uribe =- On MyFacesResponseStateManager was added
+ // some methods to discover it programatically.
+ if (StateCacheUtils.isMyFacesResponseStateManager(rsm))
+ {
+ if (StateCacheUtils.getMyFacesResponseStateManager(rsm).isWriteStateAfterRenderViewRequired(context))
+ {
+ stateWriter.writingState();
+ }
+ else
+ {
+ stateWriter.writingStateWithoutWrapper();
+ }
+ }
+ else
+ {
+ stateWriter.writingState();
+ }
+
+
}else
{
//we're in a JSP, let the JSPStatemanager know that we need to actually write the state
Copied: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ClientSideStateCacheImpl.java (from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ClientSideStateCacheImpl.java?p2=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ClientSideStateCacheImpl.java&p1=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java&r1=1102114&r2=1102936&rev=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ClientSideStateCacheImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ClientSideStateCacheImpl.java Sat May 14 01:05:41 2011
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.myfaces.renderkit.html;
+package org.apache.myfaces.renderkit;
import javax.faces.context.FacesContext;
@@ -39,4 +39,17 @@ class ClientSideStateCacheImpl extends S
return viewState;
}
+ @Override
+ public Object encodeSerializedState(FacesContext facesContext,
+ Object serializedView)
+ {
+ return serializedView;
+ }
+
+ @Override
+ public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
+ {
+ return true;
+ }
+
}
Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/MyfacesResponseStateManager.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/MyfacesResponseStateManager.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/MyfacesResponseStateManager.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/MyfacesResponseStateManager.java Sat May 14 01:05:41 2011
@@ -41,4 +41,26 @@ public abstract class MyfacesResponseSta
{
throw new UnsupportedOperationException("long been deprecated...");
}
+
+ /**
+ * Execute additional operations like save the state on a cache when server
+ * side state saving is used.
+ */
+ public void saveState(FacesContext facesContext, Object state)
+ {
+ }
+
+ /**
+ * Indicates if the call to ResponseStateManager.writeState should be done after the view is fully rendered.
+ * Usually this is required for client side state saving, but it is not for server side state saving, because
+ * ResponseStateManager.writeState could render a just a marker and then StateManager.saveState could be called,
+ * preventing use an additional buffer.
+ *
+ * @param facesContext
+ * @return
+ */
+ public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
+ {
+ return true;
+ }
}
Copied: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java (from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java?p2=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java&p1=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java&r1=1102114&r2=1102936&rev=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/ServerSideStateCacheImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java Sat May 14 01:05:41 2011
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.myfaces.renderkit.html;
+package org.apache.myfaces.renderkit;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -44,21 +44,24 @@ import javax.faces.context.FacesContext;
import org.apache.commons.collections.map.AbstractReferenceMap;
import org.apache.commons.collections.map.ReferenceMap;
import org.apache.myfaces.application.StateCache;
-import org.apache.myfaces.application.StateCacheImpl;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
import org.apache.myfaces.shared_impl.renderkit.RendererUtils;
import org.apache.myfaces.shared_impl.util.MyFacesObjectInputStream;
+import org.apache.myfaces.shared_impl.util.WebConfigParamUtils;
class ServerSideStateCacheImpl extends StateCache<Object, Object>
{
- private static final Logger log = Logger.getLogger(StateCacheImpl.class.getName());
+ private static final Logger log = Logger.getLogger(ServerSideStateCacheImpl.class.getName());
private static final String SERIALIZED_VIEW_SESSION_ATTR=
- StateCacheImpl.class.getName() + ".SERIALIZED_VIEW";
+ ServerSideStateCacheImpl.class.getName() + ".SERIALIZED_VIEW";
private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
- StateCacheImpl.class.getName() + ".RESTORED_SERIALIZED_VIEW";
+ ServerSideStateCacheImpl.class.getName() + ".RESTORED_SERIALIZED_VIEW";
+ private static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
+ ServerSideStateCacheImpl.class.getName() + ".RESTORED_VIEW_KEY";
+
/**
* Only applicable if state saving method is "server" (= default).
* Defines the amount (default = 20) of the latest views are stored in session.
@@ -67,6 +70,18 @@ class ServerSideStateCacheImpl extends S
private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM = "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
/**
+ * Only applicable if state saving method is "server" (= default).
+ * Indicates the amount of views (default is not active) that should be stored in session between sequential
+ * POST or POST-REDIRECT-GET if org.apache.myfaces.USE_FLASH_SCOPE_PURGE_VIEWS_IN_SESSION is true.
+ * <p>For example, if this param has value = 2 and in your custom webapp there is a form that is clicked 3 times, only 2 views
+ * will be stored and the third one (the one stored the first time) will be removed from session, even if the view can
+ * store more sessions org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION. This feature becomes useful for multi-window applications.
+ * where without this feature a window can swallow all view slots so the other ones will throw ViewExpiredException.</p>
+ */
+ @JSFWebConfigParam(since="2.0.6")
+ private static final String NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM = "org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION";
+
+ /**
* Default value for <code>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</code> context parameter.
*/
private static final int DEFAULT_NUMBER_OF_VIEWS_IN_SESSION = 20;
@@ -138,10 +153,24 @@ class ServerSideStateCacheImpl extends S
private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF = "off";
+ /**
+ * Only applicable if state saving method is "server" (= default).
+ * Allow use flash scope to keep track of the views used in session and the previous ones,
+ * so server side state saving can delete old views even if POST-REDIRECT-GET pattern is used.
+ * The default value is false.
+ */
+ @JSFWebConfigParam(since="2.0.6", defaultValue="false", expectedValues="true, false")
+ private static final String USE_FLASH_SCOPE_PURGE_VIEWS_IN_SESSION = "org.apache.myfaces.USE_FLASH_SCOPE_PURGE_VIEWS_IN_SESSION";
+
private static final int UNCOMPRESSED_FLAG = 0;
private static final int COMPRESSED_FLAG = 1;
private static final int JSF_SEQUENCE_INDEX = 0;
+
+ private Boolean _useFlashScopePurgeViewsInSession = null;
+
+ private Integer _numberOfSequentialViewsInSession = null;
+ private boolean _numberOfSequentialViewsInSessionSet = false;
//------------------------------------- METHODS COPIED FROM JspStateManagerImpl--------------------------------
@@ -169,7 +198,35 @@ class ServerSideStateCacheImpl extends S
viewCollection = new SerializedViewCollection();
sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
}
- viewCollection.add(context, serializeView(context, serializedView));
+
+ Map<Object,Object> attributeMap = context.getAttributes();
+
+ SerializedViewKey key = null;
+ if (getNumberOfSequentialViewsInSession(context.getExternalContext()) != null &&
+ getNumberOfSequentialViewsInSession(context.getExternalContext()) > 0)
+ {
+ key = (SerializedViewKey) attributeMap.get(RESTORED_VIEW_KEY_REQUEST_ATTR);
+
+ if (key == null )
+ {
+ if (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) &&
+ Boolean.TRUE.equals(context.getExternalContext().getRequestMap().get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
+ {
+ key = (SerializedViewKey) context.getExternalContext().getFlash().get(RESTORED_VIEW_KEY_REQUEST_ATTR);
+ }
+ }
+ }
+
+ viewCollection.add(context, serializeView(context, serializedView), getNextViewSequence(context), key);
+
+ /*
+ if (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) &&
+ context.getExternalContext().getFlash().isRedirect())
+ {
+ context.getExternalContext().getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, new SerializedViewKey(context));
+ context.getExternalContext().getFlash().keep(RESTORED_VIEW_KEY_REQUEST_ATTR);
+ }*/
+
// replace the value to notify the container about the change
sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
}
@@ -177,11 +234,11 @@ class ServerSideStateCacheImpl extends S
protected Object getSerializedViewFromServletSession(FacesContext context, String viewId, Integer sequence)
{
ExternalContext externalContext = context.getExternalContext();
- Map<String, Object> requestMap = externalContext.getRequestMap();
+ Map<Object, Object> attributeMap = context.getAttributes();
Object serializedView = null;
- if (requestMap.containsKey(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR))
+ if (attributeMap.containsKey(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR))
{
- serializedView = requestMap.get(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR);
+ serializedView = attributeMap.get(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR);
}
else
{
@@ -213,13 +270,26 @@ class ServerSideStateCacheImpl extends S
}
}
}
- requestMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
+ attributeMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
+
+ if (getNumberOfSequentialViewsInSession(externalContext) != null && getNumberOfSequentialViewsInSession(externalContext) > 0)
+ {
+ SerializedViewKey key = new SerializedViewKey(viewId, sequence);
+ attributeMap.put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
+
+ if (isUseFlashScopePurgeViewsInSession(externalContext))
+ {
+ externalContext.getFlash().put(RESTORED_VIEW_KEY_REQUEST_ATTR, key);
+ externalContext.getFlash().keep(RESTORED_VIEW_KEY_REQUEST_ATTR);
+ }
+ }
+
nextViewSequence(context);
}
return serializedView;
}
- protected int getNextViewSequence(FacesContext context)
+ public int getNextViewSequence(FacesContext context)
{
ExternalContext externalContext = context.getExternalContext();
@@ -232,7 +302,7 @@ class ServerSideStateCacheImpl extends S
return sequence.intValue();
}
- protected void nextViewSequence(FacesContext facescontext)
+ public void nextViewSequence(FacesContext facescontext)
{
ExternalContext externalContext = facescontext.getExternalContext();
Object sessionObj = externalContext.getSession(true);
@@ -280,11 +350,13 @@ class ServerSideStateCacheImpl extends S
os.write(UNCOMPRESSED_FLAG);
}
- Object[] stateArray = (Object[]) serializedView;
+ //Object[] stateArray = (Object[]) serializedView;
ObjectOutputStream out = new ObjectOutputStream(os);
- out.writeObject(stateArray[0]);
- out.writeObject(stateArray[1]);
+
+ out.writeObject(serializedView);
+ //out.writeObject(stateArray[0]);
+ //out.writeObject(stateArray[1]);
out.close();
baos.close();
@@ -366,17 +438,19 @@ class ServerSideStateCacheImpl extends S
Object object = null;
if (System.getSecurityManager() != null)
{
- object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object []>()
+ object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
{
- public Object[] run() throws PrivilegedActionException, IOException, ClassNotFoundException
+ public Object run() throws PrivilegedActionException, IOException, ClassNotFoundException
{
- return new Object[] {in.readObject(), in.readObject()};
+ //return new Object[] {in.readObject(), in.readObject()};
+ return in.readObject();
}
});
}
else
{
- object = new Object[] {in.readObject(), in.readObject()};
+ //object = new Object[] {in.readObject(), in.readObject()};
+ object = in.readObject();
}
return object;
}
@@ -422,30 +496,105 @@ class ServerSideStateCacheImpl extends S
return null;
}
}
+
+ /*
+ public static Integer getViewSequence(FacesContext facescontext)
+ {
+ Map map = facescontext.getExternalContext().getRequestMap();
+ Integer sequence = (Integer) map.get(RendererUtils.SEQUENCE_PARAM);
+ if (sequence == null)
+ {
+ sequence = new Integer(1);
+ map.put(RendererUtils.SEQUENCE_PARAM, sequence);
+
+ synchronized (facescontext.getExternalContext().getSession(true))
+ {
+ facescontext.getExternalContext().getSessionMap().put(RendererUtils.SEQUENCE_PARAM, sequence);
+ }
+ }
+ return sequence;
+ }*/
protected static class SerializedViewCollection implements Serializable
{
private static final long serialVersionUID = -3734849062185115847L;
- private final List<Object> _keys = new ArrayList<Object>(DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
- private final Map<Object, Object> _serializedViews = new HashMap<Object, Object>();
+ private final List<SerializedViewKey> _keys = new ArrayList<SerializedViewKey>(DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
+ private final Map<SerializedViewKey, Object> _serializedViews = new HashMap<SerializedViewKey, Object>();
+
+ private final Map<SerializedViewKey, SerializedViewKey> _precedence =
+ new HashMap<SerializedViewKey, SerializedViewKey>();
// old views will be hold as soft references which will be removed by
// the garbage collector if free memory is low
private transient Map<Object, Object> _oldSerializedViews = null;
- public synchronized void add(FacesContext context, Object state)
+ public synchronized void add(FacesContext context, Object state, Integer nextSequence, SerializedViewKey previousRestoredKey)
{
- Object key = new SerializedViewKey(context);
+ SerializedViewKey key = new SerializedViewKey(context.getViewRoot().getViewId(), nextSequence);
_serializedViews.put(key, state);
+ Integer maxCount = getNumberOfSequentialViewsInSession(context);
+ if (maxCount != null)
+ {
+ if (previousRestoredKey != null)
+ {
+ _precedence.put((SerializedViewKey) key, previousRestoredKey);
+ }
+ }
+
while (_keys.remove(key));
_keys.add(key);
+ if (previousRestoredKey != null && maxCount != null && maxCount > 0)
+ {
+ int count = 0;
+ SerializedViewKey previousKey = (SerializedViewKey) key;
+ do
+ {
+ previousKey = _precedence.get(previousKey);
+ count++;
+ } while (previousKey != null && count < maxCount);
+
+ if (previousKey != null)
+ {
+ SerializedViewKey keyToRemove = (SerializedViewKey) previousKey;
+ // In theory it should be only one key but just to be sure
+ // do it in a loop, but in this case if cache old views is on,
+ // put on that map.
+ do
+ {
+ while (_keys.remove(keyToRemove));
+
+ Object oldView = _serializedViews.remove(keyToRemove);
+ if (oldView != null &&
+ !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
+ {
+ getOldSerializedViewsMap().put(keyToRemove, oldView);
+ }
+
+ keyToRemove = _precedence.remove(keyToRemove);
+ } while(keyToRemove != null);
+ }
+ }
+
int views = getNumberOfViewsInSession(context);
while (_keys.size() > views)
{
key = _keys.remove(0);
+
+ if (maxCount != null && maxCount > 0)
+ {
+ SerializedViewKey keyToRemove = (SerializedViewKey) key;
+ // Note in this case the key to delete is the oldest one,
+ // so it could be at least one precedence, but to be safe
+ // do it with a loop.
+ do
+ {
+ keyToRemove = _precedence.remove(keyToRemove);
+ } while (keyToRemove != null);
+ }
+
Object oldView = _serializedViews.remove(key);
if (oldView != null &&
!CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
@@ -455,6 +604,12 @@ class ServerSideStateCacheImpl extends S
}
}
+ protected Integer getNumberOfSequentialViewsInSession(FacesContext context)
+ {
+ return WebConfigParamUtils.getIntegerInitParameter(context.getExternalContext(),
+ NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
+ }
+
/**
* Reads the amount (default = 20) of views to be stored in session.
* @see NUMBER_OF_VIEWS_IN_SESSION_PARAM
@@ -587,11 +742,12 @@ class ServerSideStateCacheImpl extends S
_viewId = viewId;
}
+ /*
public SerializedViewKey(FacesContext context)
{
- _sequenceId = RendererUtils.getViewSequence(context);
+ _sequenceId = getNextViewSequence(context);
_viewId = context.getViewRoot().getViewId();
- }
+ }*/
@Override
public int hashCode()
@@ -656,12 +812,40 @@ class ServerSideStateCacheImpl extends S
return (serverStateId == null) ? null : getSerializedViewFromServletSession(facesContext, viewId, serverStateId);
}
- protected Object encodeSerializedState(FacesContext facesContext, Object serializedView)
+ public Object encodeSerializedState(FacesContext facesContext, Object serializedView)
{
Object[] identifier = new Object[2];
identifier[JSF_SEQUENCE_INDEX] = Integer.toString(getNextViewSequence(facesContext), Character.MAX_RADIX);
return identifier;
}
+ @Override
+ public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
+ {
+ return false;
+ }
+
+ //------------------------------------- Custom methods -----------------------------------------------------
+ private boolean isUseFlashScopePurgeViewsInSession(ExternalContext externalContext)
+ {
+ if (_useFlashScopePurgeViewsInSession == null)
+ {
+ _useFlashScopePurgeViewsInSession = WebConfigParamUtils.getBooleanInitParameter(
+ externalContext, USE_FLASH_SCOPE_PURGE_VIEWS_IN_SESSION, false);
+ }
+ return _useFlashScopePurgeViewsInSession;
+ }
+
+ private Integer getNumberOfSequentialViewsInSession(ExternalContext externalContext)
+ {
+ if (!_numberOfSequentialViewsInSessionSet)
+ {
+ _numberOfSequentialViewsInSession = WebConfigParamUtils.getIntegerInitParameter(
+ externalContext,
+ NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
+ _numberOfSequentialViewsInSessionSet = true;
+ }
+ return _numberOfSequentialViewsInSession;
+ }
}
Copied: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheFactoryImpl.java (from r1102114, myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheFactoryImpl.java?p2=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheFactoryImpl.java&p1=myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java&r1=1102114&r2=1102936&rev=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/StateCacheFactoryImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheFactoryImpl.java Sat May 14 01:05:41 2011
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.myfaces.renderkit.html;
+package org.apache.myfaces.renderkit;
import javax.faces.context.FacesContext;
Added: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheUtils.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheUtils.java?rev=1102936&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheUtils.java (added)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/StateCacheUtils.java Sat May 14 01:05:41 2011
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.renderkit;
+
+import javax.faces.FacesWrapper;
+import javax.faces.render.ResponseStateManager;
+
+public class StateCacheUtils
+{
+ public static boolean isMyFacesResponseStateManager(ResponseStateManager rsm)
+ {
+ if (rsm instanceof MyfacesResponseStateManager)
+ {
+ return true;
+ }
+ else
+ {
+ ResponseStateManager rsm1 = rsm;
+ while (rsm1 != null)
+ {
+ if (rsm1 instanceof MyfacesResponseStateManager)
+ {
+ return true;
+ }
+ if (rsm1 instanceof FacesWrapper)
+ {
+ rsm1 = ((FacesWrapper<? extends ResponseStateManager>) rsm1).getWrapped();
+ }
+ else
+ {
+ rsm1 = null;
+ }
+ }
+ return false;
+ }
+ }
+
+ public static MyfacesResponseStateManager getMyFacesResponseStateManager(ResponseStateManager rsm)
+ {
+ if (rsm instanceof MyfacesResponseStateManager)
+ {
+ return (MyfacesResponseStateManager) rsm;
+ }
+ else
+ {
+ ResponseStateManager rsm1 = rsm;
+ while (rsm1 != null)
+ {
+ if (rsm1 instanceof MyfacesResponseStateManager)
+ {
+ return (MyfacesResponseStateManager) rsm1;
+ }
+ if (rsm1 instanceof FacesWrapper)
+ {
+ rsm1 = ((FacesWrapper<? extends ResponseStateManager>) rsm1).getWrapped();
+ }
+ else
+ {
+ rsm1 = null;
+ }
+ }
+ return null;
+ }
+ }
+}
Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java Sat May 14 01:05:41 2011
@@ -32,6 +32,7 @@ import org.apache.myfaces.application.St
import org.apache.myfaces.application.StateCacheFactory;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
import org.apache.myfaces.renderkit.MyfacesResponseStateManager;
+import org.apache.myfaces.renderkit.StateCacheFactoryImpl;
import org.apache.myfaces.shared_impl.config.MyfacesConfig;
import org.apache.myfaces.shared_impl.renderkit.html.HTML;
import org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils;
@@ -84,7 +85,8 @@ public class HtmlResponseStateManager ex
if (isHandlingStateCachingMechanics(facesContext))
{
- token = getStateCache(facesContext).saveSerializedView(facesContext, state);
+ //token = getStateCache(facesContext).saveSerializedView(facesContext, state);
+ token = getStateCache(facesContext).encodeSerializedState(facesContext, state);
}
else
{
@@ -116,6 +118,19 @@ public class HtmlResponseStateManager ex
// renderKitId field
writeRenderKitIdField(facesContext, responseWriter);
}
+
+ @Override
+ public void saveState(FacesContext facesContext, Object state)
+ {
+ if (isHandlingStateCachingMechanics(facesContext))
+ {
+ getStateCache(facesContext).saveSerializedView(facesContext, state);
+ }
+ else
+ {
+ //This is done outside
+ }
+ }
private void writeViewStateField(FacesContext facesContext, ResponseWriter responseWriter, Object savedState)
throws IOException
@@ -285,6 +300,12 @@ public class HtmlResponseStateManager ex
return StateUtils.construct(savedState, facesContext.getExternalContext());
}
+ @Override
+ public boolean isWriteStateAfterRenderViewRequired(FacesContext facesContext)
+ {
+ return getStateCache(facesContext).isWriteStateAfterRenderViewRequired(facesContext);
+ }
+
protected StateCache getStateCache(FacesContext facesContext)
{
return _stateCacheFactory.getStateCache(facesContext);
Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/DefaultFaceletsStateManagementStrategy.java Sat May 14 01:05:41 2011
@@ -46,8 +46,6 @@ import javax.faces.view.ViewDeclarationL
import javax.faces.view.ViewDeclarationLanguageFactory;
import javax.faces.view.ViewMetadata;
-import org.apache.myfaces.application.StateCache;
-import org.apache.myfaces.application.StateCacheImpl;
import org.apache.myfaces.application.StateManagerImpl;
import org.apache.myfaces.shared_impl.renderkit.RendererUtils;
import org.apache.myfaces.shared_impl.util.ClassUtils;
Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java Sat May 14 01:05:41 2011
@@ -18,39 +18,22 @@
*/
package org.apache.myfaces.view.facelets;
-import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
-import org.apache.myfaces.config.RuntimeConfig;
-import org.apache.myfaces.shared_impl.application.DefaultViewHandlerSupport;
-import org.apache.myfaces.shared_impl.application.ViewHandlerSupport;
-import org.apache.myfaces.shared_impl.config.MyfacesConfig;
-import org.apache.myfaces.shared_impl.util.ClassUtils;
-import org.apache.myfaces.shared_impl.util.StringUtils;
-import org.apache.myfaces.shared_impl.util.WebConfigParamUtils;
-import org.apache.myfaces.shared_impl.view.ViewDeclarationLanguageBase;
-import org.apache.myfaces.view.ViewMetadataBase;
-import org.apache.myfaces.view.facelets.FaceletViewHandler.NullWriter;
-import org.apache.myfaces.view.facelets.compiler.Compiler;
-import org.apache.myfaces.view.facelets.compiler.SAXCompiler;
-import org.apache.myfaces.view.facelets.compiler.TagLibraryConfig;
-import org.apache.myfaces.view.facelets.el.LocationMethodExpression;
-import org.apache.myfaces.view.facelets.el.LocationValueExpression;
-import org.apache.myfaces.view.facelets.el.VariableMapperWrapper;
-import org.apache.myfaces.view.facelets.impl.DefaultFaceletFactory;
-import org.apache.myfaces.view.facelets.impl.DefaultResourceResolver;
-import org.apache.myfaces.view.facelets.tag.TagLibrary;
-import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorAttachedObjectTarget;
-import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorRedirectBehaviorAttachedObjectHandlerWrapper;
-import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorRedirectEventComponentWrapper;
-import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
-import org.apache.myfaces.view.facelets.tag.composite.CompositeResourceLibrary;
-import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
-import org.apache.myfaces.view.facelets.tag.jsf.core.CoreLibrary;
-import org.apache.myfaces.view.facelets.tag.jsf.html.HtmlLibrary;
-import org.apache.myfaces.view.facelets.tag.jstl.core.JstlCoreLibrary;
-import org.apache.myfaces.view.facelets.tag.jstl.fn.JstlFnLibrary;
-import org.apache.myfaces.view.facelets.tag.ui.UIDebug;
-import org.apache.myfaces.view.facelets.tag.ui.UILibrary;
-import org.apache.myfaces.view.facelets.util.ReflectionUtil;
+import java.beans.BeanDescriptor;
+import java.beans.BeanInfo;
+import java.beans.PropertyDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.Array;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.el.ELContext;
import javax.el.ELException;
@@ -98,22 +81,40 @@ import javax.faces.view.facelets.Facelet
import javax.faces.view.facelets.ResourceResolver;
import javax.faces.view.facelets.TagDecorator;
import javax.servlet.http.HttpServletResponse;
-import java.beans.BeanDescriptor;
-import java.beans.BeanInfo;
-import java.beans.PropertyDescriptor;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.Writer;
-import java.lang.reflect.Array;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+import org.apache.myfaces.config.RuntimeConfig;
+import org.apache.myfaces.shared_impl.application.DefaultViewHandlerSupport;
+import org.apache.myfaces.shared_impl.application.ViewHandlerSupport;
+import org.apache.myfaces.shared_impl.config.MyfacesConfig;
+import org.apache.myfaces.shared_impl.util.ClassUtils;
+import org.apache.myfaces.shared_impl.util.StringUtils;
+import org.apache.myfaces.shared_impl.util.WebConfigParamUtils;
+import org.apache.myfaces.shared_impl.view.ViewDeclarationLanguageBase;
+import org.apache.myfaces.view.ViewMetadataBase;
+import org.apache.myfaces.view.facelets.FaceletViewHandler.NullWriter;
+import org.apache.myfaces.view.facelets.compiler.Compiler;
+import org.apache.myfaces.view.facelets.compiler.SAXCompiler;
+import org.apache.myfaces.view.facelets.compiler.TagLibraryConfig;
+import org.apache.myfaces.view.facelets.el.LocationMethodExpression;
+import org.apache.myfaces.view.facelets.el.LocationValueExpression;
+import org.apache.myfaces.view.facelets.el.VariableMapperWrapper;
+import org.apache.myfaces.view.facelets.impl.DefaultFaceletFactory;
+import org.apache.myfaces.view.facelets.impl.DefaultResourceResolver;
+import org.apache.myfaces.view.facelets.tag.TagLibrary;
+import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorAttachedObjectTarget;
+import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorRedirectBehaviorAttachedObjectHandlerWrapper;
+import org.apache.myfaces.view.facelets.tag.composite.ClientBehaviorRedirectEventComponentWrapper;
+import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
+import org.apache.myfaces.view.facelets.tag.composite.CompositeResourceLibrary;
+import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
+import org.apache.myfaces.view.facelets.tag.jsf.core.CoreLibrary;
+import org.apache.myfaces.view.facelets.tag.jsf.html.HtmlLibrary;
+import org.apache.myfaces.view.facelets.tag.jstl.core.JstlCoreLibrary;
+import org.apache.myfaces.view.facelets.tag.jstl.fn.JstlFnLibrary;
+import org.apache.myfaces.view.facelets.tag.ui.UIDebug;
+import org.apache.myfaces.view.facelets.tag.ui.UILibrary;
+import org.apache.myfaces.view.facelets.util.ReflectionUtil;
/**
* This class represents the abstraction of Facelets as a ViewDeclarationLanguage.
@@ -1308,12 +1309,19 @@ public class FaceletViewDeclarationLangu
{
context.setResponseWriter(writer);
- // force creation of session if saving state there
StateManager stateMgr = context.getApplication().getStateManager();
- if (!stateMgr.isSavingStateInClient(context))
- {
- extContext.getSession(true);
- }
+ // force creation of session if saving state there
+ // -= Leonardo Uribe =- Do this does not have any sense!. The only reference
+ // about these lines are on http://java.net/projects/facelets/sources/svn/revision/376
+ // and it says: "fixed lazy session instantiation with eager response commit"
+ // This code is obviously to prevent this exception:
+ // java.lang.IllegalStateException: Cannot create a session after the response has been committed
+ // But in theory if that so, StateManager.saveState must happen before writer.close() is called,
+ // which can be done very easily.
+ //if (!stateMgr.isSavingStateInClient(context))
+ //{
+ // extContext.getSession(true);
+ //}
// render the view to the response
writer.startDocument();
@@ -1323,12 +1331,23 @@ public class FaceletViewDeclarationLangu
writer.endDocument();
// finish writing
- writer.close();
+ // -= Leonardo Uribe =- This does not has sense too, because that's the reason
+ // of the try/finally block. In practice, it only forces the close of the tag
+ // in HtmlResponseWriter if necessary, but according to the spec, this should
+ // be done using writer.flush() instead.
+ // writer.close();
- boolean writtenState = stateWriter.isStateWritten();
// flush to origWriter
- if (writtenState)
+ if (stateWriter.isStateWritten())
{
+ // Call this method to force close the tag if necessary.
+ // The spec javadoc says this:
+ // "... Flush any ouput buffered by the output method to the underlying
+ // Writer or OutputStream. This method will not flush the underlying
+ // Writer or OutputStream; it simply clears any values buffered by this
+ // ResponseWriter. ..."
+ writer.flush();
+
// =-= markoc: STATE_KEY is in output ONLY if
// stateManager.isSavingStateInClient(context)is true - see
// org.apache.myfaces.application.ViewHandlerImpl.writeState(FacesContext)
@@ -1374,6 +1393,12 @@ public class FaceletViewDeclarationLangu
origWriter.write(content);
}
}
+ else if (stateWriter.isStateWrittenWithoutWrapper())
+ {
+ // The state token has been written but the state has not been
+ // saved yet.
+ stateMgr.saveView(context);
+ }
}
finally
{
Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/StateWriter.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/StateWriter.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/StateWriter.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/StateWriter.java Sat May 14 01:05:41 2011
@@ -53,6 +53,7 @@ public final class StateWriter extends W
private Writer out;
private FastWriter fast;
private boolean writtenState;
+ private boolean writtenStateWithoutWrapper;
static public StateWriter getCurrentInstance()
{
@@ -99,15 +100,29 @@ public final class StateWriter extends W
if (!this.writtenState)
{
this.writtenState = true;
+ this.writtenStateWithoutWrapper = false;
this.out = this.fast = new FastWriter(this.initialSize);
}
}
-
+
public boolean isStateWritten()
{
return this.writtenState;
}
+ public void writingStateWithoutWrapper()
+ {
+ if (!this.writtenState && !this.writtenStateWithoutWrapper)
+ {
+ this.writtenStateWithoutWrapper = true;
+ }
+ }
+
+ public boolean isStateWrittenWithoutWrapper()
+ {
+ return this.writtenStateWithoutWrapper;
+ }
+
public void close() throws IOException
{
// do nothing
Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java?rev=1102936&r1=1102935&r2=1102936&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/jsp/JspViewDeclarationLanguage.java Sat May 14 01:05:41 2011
@@ -27,12 +27,14 @@ import javax.faces.FacesException;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
+import javax.faces.render.ResponseStateManager;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.jstl.core.Config;
import org.apache.myfaces.application.jsp.ServletViewResponseWrapper;
+import org.apache.myfaces.renderkit.StateCacheUtils;
import org.apache.myfaces.shared_impl.view.JspViewDeclarationLanguageBase;
import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
import org.apache.myfaces.view.facelets.tag.jsf.core.CoreLibrary;
@@ -185,6 +187,30 @@ public class JspViewDeclarationLanguage
}
}
+ /**
+ *
+ */
+ @Override
+ protected boolean isViewStateAlreadyEncoded(FacesContext context)
+ {
+ ResponseStateManager responseStateManager = context.getRenderKit().getResponseStateManager();
+ if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
+ {
+ if (StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).isWriteStateAfterRenderViewRequired(context))
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
@Override
protected void sendSourceNotFound(FacesContext context, String message)
{
Added: myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ServerSideStateCacheTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ServerSideStateCacheTest.java?rev=1102936&view=auto
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ServerSideStateCacheTest.java (added)
+++ myfaces/core/branches/2.0.x/impl/src/test/java/org/apache/myfaces/renderkit/ServerSideStateCacheTest.java Sat May 14 01:05:41 2011
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.renderkit;
+
+import javax.faces.application.StateManager;
+
+import org.apache.myfaces.application.StateCache;
+import org.apache.myfaces.test.base.junit4.AbstractJsfConfigurableMultipleRequestsTestCase;
+import org.junit.Test;
+import org.testng.Assert;
+
+public class ServerSideStateCacheTest extends AbstractJsfConfigurableMultipleRequestsTestCase
+{
+
+ @Test
+ public void testNumberOfSequentialViewsInSession() throws Exception
+ {
+
+ servletContext.addInitParameter(StateManager.STATE_SAVING_METHOD_PARAM_NAME, StateManager.STATE_SAVING_METHOD_SERVER);
+ servletContext.addInitParameter("org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION", "5");
+ servletContext.addInitParameter("org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION", "2");
+
+ StateCache stateCache = new ServerSideStateCacheImpl();
+
+ Object savedToken;
+ Object firstSavedToken;
+
+ try
+ {
+ setupRequest();
+
+ facesContext.getViewRoot().setViewId("view1.xhtml");
+ savedToken = stateCache.saveSerializedView(facesContext, 1);
+ firstSavedToken = savedToken;
+ }
+ finally
+ {
+ tearDownRequest();
+ }
+
+ try
+ {
+ setupRequest();
+
+ Object value = stateCache.restoreSerializedView(facesContext, "view1.xhtml", savedToken);
+
+ Assert.assertEquals(1, value);
+
+ facesContext.getViewRoot().setViewId("view2.xhtml");
+ savedToken = stateCache.saveSerializedView(facesContext, 2);
+ }
+ finally
+ {
+ tearDownRequest();
+ }
+
+ try
+ {
+ setupRequest();
+
+ Object value = stateCache.restoreSerializedView(facesContext, "view2.xhtml", savedToken);
+
+ Assert.assertEquals(2, value);
+
+ facesContext.getViewRoot().setViewId("view2.xhtml");
+ savedToken = stateCache.saveSerializedView(facesContext, 3);
+ }
+ finally
+ {
+ tearDownRequest();
+ }
+
+ try
+ {
+ setupRequest();
+
+ Object value = stateCache.restoreSerializedView(facesContext, "view1.xhtml", firstSavedToken);
+
+ // Since org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION is 2, the first one was already discarded
+ Assert.assertNull(value);
+ }
+ finally
+ {
+ tearDownRequest();
+ }
+
+
+ }
+}