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 2014/11/01 00:56:10 UTC
svn commit: r1635886 - in /myfaces/core/trunk:
impl/src/main/java/org/apache/myfaces/application/viewstate/ shared/
shared/src/main/java/org/apache/myfaces/shared/config/
shared/src/main/java/org/apache/myfaces/shared/context/flash/
shared/src/test/jav...
Author: lu4242
Date: Fri Oct 31 23:56:09 2014
New Revision: 1635886
URL: http://svn.apache.org/r1635886
Log:
MYFACES-3936 Flash object requires cleanup strategy when client window feature is used
Added:
myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/ClientWindowFlashTokenLRUMap.java
myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashClientWindowTokenCollection.java
myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/ReleasableFlash.java
Modified:
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/viewstate/SerializedViewCollection.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/viewstate/ServerSideStateCacheImpl.java
myfaces/core/trunk/shared/pom.xml
myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java
myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java
myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/context/flash/FlashImplTest.java
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/viewstate/SerializedViewCollection.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/viewstate/SerializedViewCollection.java?rev=1635886&r1=1635885&r2=1635886&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/viewstate/SerializedViewCollection.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/viewstate/SerializedViewCollection.java Fri Oct 31 23:56:09 2014
@@ -23,11 +23,10 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.context.FacesContext;
import org.apache.commons.collections.map.LRUMap;
-import org.apache.myfaces.shared.util.WebConfigParamUtils;
+import org.apache.myfaces.shared.config.MyfacesConfig;
import org.apache.myfaces.spi.ViewScopeProvider;
/**
@@ -42,7 +41,7 @@ class SerializedViewCollection implement
private static final long serialVersionUID = -3734849062185115847L;
private final List<SerializedViewKey> _keys =
new ArrayList<SerializedViewKey>(
- ServerSideStateCacheImpl.DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
+ MyfacesConfig.INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION_DEFAULT);
private final Map<SerializedViewKey, Object> _serializedViews =
new HashMap<SerializedViewKey, Object>();
/**
@@ -233,8 +232,7 @@ class SerializedViewCollection implement
protected Integer getNumberOfSequentialViewsInSession(FacesContext context)
{
- return WebConfigParamUtils.getIntegerInitParameter( context.getExternalContext(),
- ServerSideStateCacheImpl.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
+ return MyfacesConfig.getCurrentInstance(context.getExternalContext()).getNumberOfSequentialViewsInSession();
}
/**
@@ -245,31 +243,7 @@ class SerializedViewCollection implement
*/
protected int getNumberOfViewsInSession(FacesContext context)
{
- String value = context.getExternalContext().getInitParameter(
- ServerSideStateCacheImpl.NUMBER_OF_VIEWS_IN_SESSION_PARAM);
- int views = ServerSideStateCacheImpl.DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
- if (value != null)
- {
- try
- {
- views = Integer.parseInt(value);
- if (views <= 0)
- {
- log.severe("Configured value for " + ServerSideStateCacheImpl.NUMBER_OF_VIEWS_IN_SESSION_PARAM
- + " is not valid, must be an value > 0, using default value ("
- + ServerSideStateCacheImpl.DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
- views = ServerSideStateCacheImpl.DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
- }
- }
- catch (Throwable e)
- {
- log.log( Level.SEVERE, "Error determining the value for "
- + ServerSideStateCacheImpl.NUMBER_OF_VIEWS_IN_SESSION_PARAM
- + ", expected an integer value > 0, using default value ("
- + ServerSideStateCacheImpl.DEFAULT_NUMBER_OF_VIEWS_IN_SESSION + "): " + e.getMessage(), e);
- }
- }
- return views;
+ return MyfacesConfig.getCurrentInstance(context.getExternalContext()).getNumberOfViewsInSession();
}
public synchronized void putLastWindowKey(FacesContext context, String id, SerializedViewKey key)
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/viewstate/ServerSideStateCacheImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/viewstate/ServerSideStateCacheImpl.java?rev=1635886&r1=1635885&r2=1635886&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/viewstate/ServerSideStateCacheImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/viewstate/ServerSideStateCacheImpl.java Fri Oct 31 23:56:09 2014
@@ -42,6 +42,7 @@ import javax.faces.lifecycle.ClientWindo
import org.apache.myfaces.application.StateCache;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+import org.apache.myfaces.shared.config.MyfacesConfig;
import org.apache.myfaces.shared.renderkit.RendererUtils;
import org.apache.myfaces.shared.util.MyFacesObjectInputStream;
import org.apache.myfaces.shared.util.WebConfigParamUtils;
@@ -67,37 +68,13 @@ class ServerSideStateCacheImpl extends S
public static final String RESTORED_VIEW_KEY_REQUEST_ATTR =
ServerSideStateCacheImpl.class.getName() + ".RESTORED_VIEW_KEY";
- /**
- * Defines the amount (default = 20) of the latest views are stored in session.
- *
- * <p>Only applicable if state saving method is "server" (= default).
- * </p>
- *
- */
- @JSFWebConfigParam(defaultValue="20",since="1.1", classType="java.lang.Integer", group="state", tags="performance")
- public static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM = "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
+ public static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM = MyfacesConfig.INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION;
- /**
- * Indicates the amount of views (default is not active) that should be stored in session between sequential
- * POST or POST-REDIRECT-GET if org.apache.myfaces.USE_FLASH_SCOPE_PURGE_VIEWS_IN_SESSION is true.
- *
- * <p>Only applicable if state saving method is "server" (= default). For example, if this param has value = 2 and
- * 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", classType="java.lang.Integer", group="state", tags="performance")
public static final String NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM
- = "org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION";
+ = MyfacesConfig.INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION;
- /**
- * Default value for <code>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</code> context parameter.
- */
- public static final int DEFAULT_NUMBER_OF_VIEWS_IN_SESSION = 20;
+ public static final int DEFAULT_NUMBER_OF_VIEWS_IN_SESSION =
+ MyfacesConfig.INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION_DEFAULT;
/**
* Indicate if the state should be serialized before save it on the session.
@@ -714,9 +691,8 @@ class ServerSideStateCacheImpl extends S
{
if (!_numberOfSequentialViewsInSessionSet)
{
- _numberOfSequentialViewsInSession = WebConfigParamUtils.getIntegerInitParameter(
- externalContext,
- NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_PARAM);
+ _numberOfSequentialViewsInSession = MyfacesConfig.getCurrentInstance(externalContext)
+ .getNumberOfSequentialViewsInSession();
_numberOfSequentialViewsInSessionSet = true;
}
return _numberOfSequentialViewsInSession;
Modified: myfaces/core/trunk/shared/pom.xml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/pom.xml?rev=1635886&r1=1635885&r2=1635886&view=diff
==============================================================================
--- myfaces/core/trunk/shared/pom.xml (original)
+++ myfaces/core/trunk/shared/pom.xml Fri Oct 31 23:56:09 2014
@@ -77,6 +77,11 @@
</dependency>
<dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
Modified: myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java?rev=1635886&r1=1635885&r2=1635886&view=diff
==============================================================================
--- myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java (original)
+++ myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java Fri Oct 31 23:56:09 2014
@@ -19,6 +19,8 @@
package org.apache.myfaces.shared.config;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.faces.context.ExternalContext;
import javax.servlet.ServletContext;
@@ -475,7 +477,52 @@ public class MyfacesConfig
@JSFWebConfigParam(defaultValue="false",since="2.0.5")
public static final String INIT_PARAM_FLASH_SCOPE_DISABLED = "org.apache.myfaces.FLASH_SCOPE_DISABLED";
public static final boolean INIT_PARAM_FLASH_SCOPE_DISABLED_DEFAULT = false;
+
+ /**
+ * Defines the amount (default = 20) of the latest views are stored in session.
+ *
+ * <p>Only applicable if state saving method is "server" (= default).
+ * </p>
+ *
+ */
+ @JSFWebConfigParam(defaultValue="20",since="1.1", classType="java.lang.Integer", group="state", tags="performance")
+ public static final String INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION = "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
+
+ /**
+ * Default value for <code>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</code> context parameter.
+ */
+ public static final int INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION_DEFAULT = 20;
+ /**
+ * Indicates the amount of views (default is not active) that should be stored in session between sequential
+ * POST or POST-REDIRECT-GET if org.apache.myfaces.USE_FLASH_SCOPE_PURGE_VIEWS_IN_SESSION is true.
+ *
+ * <p>Only applicable if state saving method is "server" (= default). For example, if this param has value = 2 and
+ * 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", classType="java.lang.Integer", group="state", tags="performance",
+ defaultValue = "4")
+ public static final String INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION
+ = "org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION";
+ public static final Integer INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_DEFAULT = 4;
+
+ /**
+ * Indicate the max number of flash tokens stored into session. It is only active when
+ * javax.faces.CLIENT_WINDOW_MODE is enabled. Each flash token is associated to one client window id at
+ * the same time, so this param is related to the limit of active client windows per session.
+ * By default is the same number as in
+ * (org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION /
+ * org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION) + 1 = 6.
+ */
+ @JSFWebConfigParam(since="2.2.6", group="state", tags="performance")
+ static final String NUMBER_OF_FLASH_TOKENS_IN_SESSION = "org.apache.myfaces.NUMBER_OF_FLASH_TOKENS_IN_SESSION";
+
private boolean _prettyHtml;
private boolean _detectJavascript;
private boolean _allowJavascript;
@@ -514,6 +561,9 @@ public class MyfacesConfig
private boolean _strictJsf2FaceletsCompatibility;
private boolean _renderFormViewStateAtBegin;
private boolean _flashScopeDisabled;
+ private Integer _numberOfViewsInSession;
+ private Integer _numberOfSequentialViewsInSession;
+ private Integer _numberOfFlashTokensInSession;
private static final boolean TOMAHAWK_AVAILABLE;
private static final boolean MYFACES_IMPL_AVAILABLE;
@@ -621,6 +671,11 @@ public class MyfacesConfig
setStrictJsf2FaceletsCompatibility(INIT_PARAM_STRICT_JSF_2_FACELETS_COMPATIBILITY_DEFAULT);
setRenderFormViewStateAtBegin(INIT_PARAM_RENDER_FORM_VIEW_STATE_AT_BEGIN_DEFAULT);
setFlashScopeDisabled(INIT_PARAM_FLASH_SCOPE_DISABLED_DEFAULT);
+ setNumberOfViewsInSession(INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION_DEFAULT);
+ setNumberOfSequentialViewsInSession(INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_DEFAULT);
+ setNumberOfFlashTokensInSession(
+ (INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION_DEFAULT /
+ INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_DEFAULT)+1);
}
private static MyfacesConfig createAndInitializeMyFacesConfig(ExternalContext extCtx)
@@ -751,6 +806,68 @@ public class MyfacesConfig
INIT_PARAM_FLASH_SCOPE_DISABLED,
INIT_PARAM_FLASH_SCOPE_DISABLED_DEFAULT));
+ try
+ {
+ myfacesConfig.setNumberOfSequentialViewsInSession(WebConfigParamUtils.getIntegerInitParameter(
+ extCtx,
+ INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION,
+ INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_DEFAULT));
+ Integer views = myfacesConfig.getNumberOfSequentialViewsInSession();
+ if (views == null || views < 0)
+ {
+ Logger.getLogger(MyfacesConfig.class.getName()).severe(
+ "Configured value for " + INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION
+ + " is not valid, must be an value >= 0, using default value ("
+ + INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_DEFAULT);
+ views = INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_DEFAULT;
+ }
+ }
+ catch (Throwable e)
+ {
+ Logger.getLogger(MyfacesConfig.class.getName()).log(Level.SEVERE, "Error determining the value for "
+ + INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION
+ + ", expected an integer value > 0, using default value ("
+ + INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_DEFAULT + "): " + e.getMessage(), e);
+ }
+ try
+ {
+ myfacesConfig.setNumberOfViewsInSession(WebConfigParamUtils.getIntegerInitParameter(
+ extCtx,
+ INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION,
+ INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION_DEFAULT));
+ Integer views = myfacesConfig.getNumberOfViewsInSession();
+ if (views == null || views <= 0)
+ {
+ Logger.getLogger(MyfacesConfig.class.getName()).severe(
+ "Configured value for " + INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION
+ + " is not valid, must be an value > 0, using default value ("
+ + INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION_DEFAULT);
+ views = INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION_DEFAULT;
+ }
+ }
+ catch (Throwable e)
+ {
+ Logger.getLogger(MyfacesConfig.class.getName()).log(Level.SEVERE, "Error determining the value for "
+ + INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION
+ + ", expected an integer value > 0, using default value ("
+ + INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION_DEFAULT + "): " + e.getMessage(), e);
+ }
+
+ Integer numberOfFlashTokensInSessionDefault;
+ Integer i = myfacesConfig.getNumberOfSequentialViewsInSession();
+ int j = myfacesConfig.getNumberOfViewsInSession();
+ if (i != null && i.intValue() > 0)
+ {
+ numberOfFlashTokensInSessionDefault = (j / i.intValue()) + 1;
+ }
+ else
+ {
+ numberOfFlashTokensInSessionDefault = j + 1;
+ }
+ myfacesConfig.setNumberOfFlashTokensInSession(WebConfigParamUtils.getIntegerInitParameter(
+ extCtx,
+ INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION, numberOfFlashTokensInSessionDefault));
+
if (TOMAHAWK_AVAILABLE)
{
myfacesConfig.setDetectJavascript(getBooleanInitParameter(extCtx, INIT_PARAM_DETECT_JAVASCRIPT,
@@ -1338,4 +1455,52 @@ public class MyfacesConfig
{
this._flashScopeDisabled = flashScopeDisabled;
}
+
+ /**
+ * @return the _numberOfViewsInSession
+ */
+ public Integer getNumberOfViewsInSession()
+ {
+ return _numberOfViewsInSession;
+ }
+
+ /**
+ * @param _numberOfViewsInSession the _numberOfViewsInSession to set
+ */
+ public void setNumberOfViewsInSession(Integer numberOfViewsInSession)
+ {
+ this._numberOfViewsInSession = numberOfViewsInSession;
+ }
+
+ /**
+ * @return the _numberOfSequentialViewsInSession
+ */
+ public Integer getNumberOfSequentialViewsInSession()
+ {
+ return _numberOfSequentialViewsInSession;
+ }
+
+ /**
+ * @param _numberOfSequentialViewsInSession the _numberOfSequentialViewsInSession to set
+ */
+ public void setNumberOfSequentialViewsInSession(Integer numberOfSequentialViewsInSession)
+ {
+ this._numberOfSequentialViewsInSession = numberOfSequentialViewsInSession;
+ }
+
+ /**
+ * @return the _numberOfFlashTokensInSession
+ */
+ public Integer getNumberOfFlashTokensInSession()
+ {
+ return _numberOfFlashTokensInSession;
+ }
+
+ /**
+ * @param _numberOfFlashTokensInSession the _numberOfFlashTokensInSession to set
+ */
+ public void setNumberOfFlashTokensInSession(Integer numberOfFlashTokensInSession)
+ {
+ this._numberOfFlashTokensInSession = numberOfFlashTokensInSession;
+ }
}
Added: myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/ClientWindowFlashTokenLRUMap.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/ClientWindowFlashTokenLRUMap.java?rev=1635886&view=auto
==============================================================================
--- myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/ClientWindowFlashTokenLRUMap.java (added)
+++ myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/ClientWindowFlashTokenLRUMap.java Fri Oct 31 23:56:09 2014
@@ -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.shared.context.flash;
+
+import java.io.Serializable;
+import java.util.Map;
+import javax.faces.FacesWrapper;
+import javax.faces.context.FacesContext;
+import javax.faces.context.Flash;
+import org.apache.commons.collections.map.LRUMap;
+
+/**
+ *
+ */
+class ClientWindowFlashTokenLRUMap extends LRUMap implements Serializable
+{
+
+ public ClientWindowFlashTokenLRUMap()
+ {
+ }
+
+ public ClientWindowFlashTokenLRUMap(int maxSize)
+ {
+ super(maxSize);
+ }
+
+ public ClientWindowFlashTokenLRUMap(int maxSize, boolean scanUntilRemovable)
+ {
+ super(maxSize, scanUntilRemovable);
+ }
+
+ public ClientWindowFlashTokenLRUMap(int maxSize, float loadFactor)
+ {
+ super(maxSize, loadFactor);
+ }
+
+ public ClientWindowFlashTokenLRUMap(int maxSize, float loadFactor, boolean scanUntilRemovable)
+ {
+ super(maxSize, loadFactor, scanUntilRemovable);
+ }
+
+ public ClientWindowFlashTokenLRUMap(Map map)
+ {
+ super(map);
+ }
+
+ public ClientWindowFlashTokenLRUMap(Map map, boolean scanUntilRemovable)
+ {
+ super(map, scanUntilRemovable);
+ }
+
+ public synchronized String getValue(String key)
+ {
+ return (String) get(key);
+ }
+
+ @Override
+ protected boolean removeLRU(LinkEntry entry)
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ Flash flash = facesContext.getExternalContext().getFlash();
+ if (flash != null)
+ {
+ ReleasableFlash rf = null;
+ while (flash != null)
+ {
+ if (flash instanceof ReleasableFlash)
+ {
+ rf = (ReleasableFlash) flash;
+ break;
+ }
+ if (flash instanceof FacesWrapper)
+ {
+ flash = ((FacesWrapper<? extends Flash>) flash).getWrapped();
+ }
+ else
+ {
+ flash = null;
+ }
+ }
+ if (rf != null)
+ {
+ rf.clearFlashMap(facesContext, (String) entry.getKey(), (String) entry.getValue());
+ }
+ }
+ return super.removeLRU(entry);
+ }
+}
Added: myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashClientWindowTokenCollection.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashClientWindowTokenCollection.java?rev=1635886&view=auto
==============================================================================
--- myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashClientWindowTokenCollection.java (added)
+++ myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashClientWindowTokenCollection.java Fri Oct 31 23:56:09 2014
@@ -0,0 +1,58 @@
+/*
+ * 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.shared.context.flash;
+
+import java.io.Serializable;
+
+/**
+ * This class is a wrapper used to deal with concurrency issues when accessing the inner LRUMap.
+ */
+class FlashClientWindowTokenCollection implements Serializable
+{
+ private ClientWindowFlashTokenLRUMap lruMap;
+
+ public FlashClientWindowTokenCollection(ClientWindowFlashTokenLRUMap lruMap)
+ {
+ this.lruMap = lruMap;
+ }
+
+ public FlashClientWindowTokenCollection()
+ {
+ }
+
+ public synchronized void put(String key, String value)
+ {
+ lruMap.put(key, value);
+ }
+
+ public synchronized String get(String key)
+ {
+ return (String) lruMap.get(key);
+ }
+
+ public synchronized void remove(String key)
+ {
+ lruMap.remove(key);
+ }
+
+ public synchronized boolean isEmpty()
+ {
+ return lruMap.isEmpty();
+ }
+}
Modified: myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java?rev=1635886&r1=1635885&r2=1635886&view=diff
==============================================================================
--- myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java (original)
+++ myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java Fri Oct 31 23:56:09 2014
@@ -51,7 +51,7 @@ import org.apache.myfaces.shared.util.Se
/**
* Implementation of Flash object
*/
-public class FlashImpl extends Flash
+public class FlashImpl extends Flash implements ReleasableFlash
{
// ~ static fields --------------------------------------------------------
@@ -117,6 +117,8 @@ public class FlashImpl extends Flash
*/
static final String FLASH_EXECUTE_MAP_TOKEN = FLASH_PREFIX + ".EXECUTEMAP.TOKEN";
+ static final String FLASH_CW_LRU_MAP = FLASH_PREFIX + ".CW.LRUMAP";
+
/**
* Token separator.
*/
@@ -267,6 +269,8 @@ public class FlashImpl extends Flash
// was already performed and the response has already been committed,
// because the renderMap is stored in the session.
_saveMessages(facesContext);
+
+ _clearRenderFlashTokenIfMapEmpty(facesContext);
}
}
}
@@ -751,9 +755,8 @@ public class FlashImpl extends Flash
ClientWindow clientWindow = externalContext.getClientWindow();
if (clientWindow != null)
{
- //Use HttpSession or PortletSession object
- Map<String, Object> sessionMap = externalContext.getSessionMap();
- sessionMap.put(FLASH_RENDER_MAP_TOKEN+SEPARATOR_CHAR+clientWindow.getId(), tokenValue);
+ FlashClientWindowTokenCollection lruMap = getFlashClientWindowTokenCollection(externalContext, true);
+ lruMap.put(clientWindow.getId(), tokenValue);
}
else
{
@@ -786,9 +789,11 @@ public class FlashImpl extends Flash
ClientWindow clientWindow = externalContext.getClientWindow();
if (clientWindow != null)
{
- Map<String, Object> sessionMap = externalContext.getSessionMap();
- tokenValue = (String) sessionMap.get(FLASH_RENDER_MAP_TOKEN+
- SEPARATOR_CHAR+clientWindow.getId());
+ FlashClientWindowTokenCollection lruMap = getFlashClientWindowTokenCollection(externalContext, false);
+ if (lruMap != null)
+ {
+ tokenValue = (String) lruMap.get(clientWindow.getId());
+ }
}
else
{
@@ -836,9 +841,19 @@ public class FlashImpl extends Flash
{
if (facesContext.isPostback())
{
- // on a postback, we should always have a previousToken
- log.warning("Identifier for execute FlashMap was lost on " +
- "the postback, thus FlashScope information is gone.");
+ if (facesContext.getExternalContext().getClientWindow() == null)
+ {
+ // on a postback, we should always have a previousToken
+ log.warning("Identifier for execute FlashMap was lost on " +
+ "the postback, thus FlashScope information is gone.");
+ }
+ else
+ {
+ // Next token was not preserved in session, which means flash map
+ // is empty. Create a new token and store it as execute map, which
+ // will be empty.
+ requestMap.put(FLASH_EXECUTE_MAP_TOKEN, _getNextToken());
+ }
}
// create a new token (and thus a new Map) for this request's
@@ -906,7 +921,7 @@ public class FlashImpl extends Flash
if (map == null)
{
String token = (String) requestMap.get(FLASH_RENDER_MAP_TOKEN);
- String fullToken = FLASH_SESSION_MAP_SUBKEY_PREFIX + SEPARATOR_CHAR + token;
+ String fullToken = FLASH_SESSION_MAP_SUBKEY_PREFIX + SEPARATOR_CHAR + token + SEPARATOR_CHAR;
map = _createSubKeyMap(context, fullToken);
requestMap.put(FLASH_RENDER_MAP, map);
}
@@ -933,7 +948,7 @@ public class FlashImpl extends Flash
if (map == null)
{
String token = (String) requestMap.get(FLASH_EXECUTE_MAP_TOKEN);
- String fullToken = FLASH_SESSION_MAP_SUBKEY_PREFIX + SEPARATOR_CHAR + token;
+ String fullToken = FLASH_SESSION_MAP_SUBKEY_PREFIX + SEPARATOR_CHAR + token + SEPARATOR_CHAR;
map = _createSubKeyMap(context, fullToken);
requestMap.put(FLASH_EXECUTE_MAP, map);
}
@@ -1041,6 +1056,82 @@ public class FlashImpl extends Flash
// always be an execute Map, however sometimes an empty one!
map.clear();
}
+
+ private void _clearRenderFlashTokenIfMapEmpty(FacesContext facesContext)
+ {
+ // Keep in mind that we cannot remove a cookie once the response has been sent,
+ // but we can remove an attribute from session anytime, so the idea is check
+ // if the map is empty or not and if that so, do not save the token. The effect
+ // is we can reduce the session size a bit.
+ ExternalContext externalContext = facesContext.getExternalContext();
+ Object session = facesContext.getExternalContext().getSession(false);
+ ClientWindow clientWindow = externalContext.getClientWindow();
+ if (session != null && clientWindow != null)
+ {
+ Map<String, Object> map = _getRenderFlashMap(facesContext);
+ if (map.isEmpty())
+ {
+ // Remove token, because it is not necessary
+ FlashClientWindowTokenCollection lruMap = getFlashClientWindowTokenCollection(externalContext, false);
+ if (lruMap != null)
+ {
+ lruMap.remove(clientWindow.getId());
+ Map<String, Object> sessionMap = externalContext.getSessionMap();
+ if (lruMap.isEmpty())
+ {
+ sessionMap.remove(FLASH_CW_LRU_MAP);
+ }
+ else
+ {
+ //refresh remove
+ sessionMap.put(FLASH_CW_LRU_MAP, lruMap);
+ }
+ }
+ }
+ }
+ }
+
+ protected FlashClientWindowTokenCollection getFlashClientWindowTokenCollection(
+ ExternalContext externalContext, boolean create)
+ {
+ Object session = externalContext.getSession(false);
+ if (session == null && !create)
+ {
+ return null;
+ }
+ Map<String, Object> sessionMap = externalContext.getSessionMap();
+ FlashClientWindowTokenCollection lruMap = (FlashClientWindowTokenCollection)
+ sessionMap.get(FLASH_CW_LRU_MAP);
+ if (lruMap == null)
+ {
+ Integer ft = MyfacesConfig.getCurrentInstance(externalContext).getNumberOfFlashTokensInSession();
+ lruMap = new FlashClientWindowTokenCollection(new ClientWindowFlashTokenLRUMap(ft));
+ }
+
+ if (create)
+ {
+ sessionMap.put(FLASH_CW_LRU_MAP, lruMap);
+ }
+ return lruMap;
+ }
+
+ public void clearFlashMap(FacesContext facesContext, String clientWindowId, String token)
+ {
+ if (!_flashScopeDisabled)
+ {
+ ExternalContext externalContext = facesContext.getExternalContext();
+ ClientWindow clientWindow = externalContext.getClientWindow();
+ if (clientWindow != null)
+ {
+ if (token != null)
+ {
+ String fullToken = FLASH_SESSION_MAP_SUBKEY_PREFIX + SEPARATOR_CHAR + token + SEPARATOR_CHAR;
+ Map<String, Object> map = _createSubKeyMap(facesContext, fullToken);
+ map.clear();
+ }
+ }
+ }
+ }
/**
* Creates a Cookie with the given name and value.
Added: myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/ReleasableFlash.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/ReleasableFlash.java?rev=1635886&view=auto
==============================================================================
--- myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/ReleasableFlash.java (added)
+++ myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/context/flash/ReleasableFlash.java Fri Oct 31 23:56:09 2014
@@ -0,0 +1,32 @@
+/*
+ * 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.shared.context.flash;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * Implement this interface, so ClientWindowFlashTokenLRUMap can remove the resources
+ * associated with the client window / flash scope token, when an entry is discarded by
+ * the LRU algorithm.
+ */
+public interface ReleasableFlash
+{
+ public void clearFlashMap(FacesContext facesContext, String clientWindowId, String token);
+
+}
Modified: myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/context/flash/FlashImplTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/context/flash/FlashImplTest.java?rev=1635886&r1=1635885&r2=1635886&view=diff
==============================================================================
--- myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/context/flash/FlashImplTest.java (original)
+++ myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/context/flash/FlashImplTest.java Fri Oct 31 23:56:09 2014
@@ -100,7 +100,7 @@ public class FlashImplTest extends Abstr
final String renderToken = (String) externalContext
.getRequestMap().get(FlashImpl.FLASH_RENDER_MAP_TOKEN);
final String sessionMapKey = FlashImpl.FLASH_SESSION_MAP_SUBKEY_PREFIX +
- FlashImpl.SEPARATOR_CHAR + renderToken + "testkey1";
+ FlashImpl.SEPARATOR_CHAR + renderToken + FlashImpl.SEPARATOR_CHAR + "testkey1";
// Assertion
Assert.assertEquals("The render FlashMap must use the session Map to store the values.",