MYFACES-3938 Faces Flow requires cleanup strategy and MYFACES-3936 Flash object requires cleanup strategy when client window feature is used
diff --git a/impl/src/main/java/org/apache/myfaces/event/PostClientWindowAndViewInitializedEvent.java b/impl/src/main/java/org/apache/myfaces/event/PostClientWindowAndViewInitializedEvent.java
new file mode 100644
index 0000000..5f898b8
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/event/PostClientWindowAndViewInitializedEvent.java
@@ -0,0 +1,34 @@
+/*
+ * 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.event;
+
+import javax.faces.event.SystemEvent;
+
+/**
+ *
+ */
+public class PostClientWindowAndViewInitializedEvent extends SystemEvent
+{
+
+ public PostClientWindowAndViewInitializedEvent(Object source)
+ {
+ super(source);
+ }
+
+}
diff --git a/impl/src/main/java/org/apache/myfaces/flow/FlowHandlerImpl.java b/impl/src/main/java/org/apache/myfaces/flow/FlowHandlerImpl.java
index ddaf59b..42f0a95 100644
--- a/impl/src/main/java/org/apache/myfaces/flow/FlowHandlerImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/flow/FlowHandlerImpl.java
@@ -30,6 +30,8 @@
import javax.faces.application.NavigationHandler;
import javax.faces.application.NavigationHandlerWrapper;
import javax.faces.context.FacesContext;
+import javax.faces.event.SystemEvent;
+import javax.faces.event.SystemEventListener;
import javax.faces.flow.Flow;
import javax.faces.flow.FlowCallNode;
import javax.faces.flow.FlowHandler;
@@ -37,6 +39,7 @@
import javax.faces.flow.Parameter;
import javax.faces.flow.ReturnNode;
import javax.faces.lifecycle.ClientWindow;
+import org.apache.myfaces.event.PostClientWindowAndViewInitializedEvent;
import org.apache.myfaces.spi.FacesFlowProvider;
import org.apache.myfaces.spi.FacesFlowProviderFactory;
@@ -45,7 +48,7 @@
* @since 2.2
* @author Leonardo Uribe
*/
-public class FlowHandlerImpl extends FlowHandler
+public class FlowHandlerImpl extends FlowHandler implements SystemEventListener
{
private final static String CURRENT_FLOW_STACK = "oam.flow.STACK.";
private final static String ROOT_LAST_VIEW_ID = "oam.flow.ROOT_LAST_VIEW_ID.";
@@ -386,6 +389,9 @@
facesContext.getExternalContext());
_facesFlowProvider = factory.getFacesFlowProvider(
facesContext.getExternalContext());
+
+ facesContext.getApplication().unsubscribeFromEvent(PostClientWindowAndViewInitializedEvent.class, this);
+ facesContext.getApplication().subscribeToEvent(PostClientWindowAndViewInitializedEvent.class, this);
}
return _facesFlowProvider;
}
@@ -1066,4 +1072,19 @@
}
}
+ @Override
+ public boolean isListenerForSource(Object source)
+ {
+ return source instanceof ClientWindow;
+ }
+
+ @Override
+ public void processEvent(SystemEvent event)
+ {
+ // refresh client window to faces flow provider
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ FacesFlowProvider provider = getFacesFlowProvider(facesContext);
+ provider.refreshClientWindow(facesContext);
+ }
+
}
diff --git a/impl/src/main/java/org/apache/myfaces/flow/cdi/ClientWindowFacesFlowLRUMap.java b/impl/src/main/java/org/apache/myfaces/flow/cdi/ClientWindowFacesFlowLRUMap.java
new file mode 100644
index 0000000..1f5b1f9
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/flow/cdi/ClientWindowFacesFlowLRUMap.java
@@ -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.flow.cdi;
+
+import java.io.Serializable;
+import java.util.Map;
+import org.apache.commons.collections.map.LRUMap;
+
+/**
+ *
+ */
+class ClientWindowFacesFlowLRUMap extends LRUMap implements Serializable
+{
+ private transient FlowScopeBeanHolder holder;
+
+ public ClientWindowFacesFlowLRUMap()
+ {
+ }
+
+ public ClientWindowFacesFlowLRUMap(int maxSize)
+ {
+ super(maxSize);
+ }
+
+ public ClientWindowFacesFlowLRUMap(int maxSize, boolean scanUntilRemovable)
+ {
+ super(maxSize, scanUntilRemovable);
+ }
+
+ public ClientWindowFacesFlowLRUMap(int maxSize, float loadFactor)
+ {
+ super(maxSize, loadFactor);
+ }
+
+ public ClientWindowFacesFlowLRUMap(int maxSize, float loadFactor, boolean scanUntilRemovable)
+ {
+ super(maxSize, loadFactor, scanUntilRemovable);
+ }
+
+ public ClientWindowFacesFlowLRUMap(Map map)
+ {
+ super(map);
+ }
+
+ public ClientWindowFacesFlowLRUMap(Map map, boolean scanUntilRemovable)
+ {
+ super(map, scanUntilRemovable);
+ }
+
+ public void setFlowScopeBeanHolder(FlowScopeBeanHolder holder)
+ {
+ this.holder = holder;
+ }
+
+ @Override
+ protected boolean removeLRU(LinkEntry entry)
+ {
+ if (holder != null)
+ {
+ holder.clearFlowMap((String) entry.getKey());
+ }
+ return super.removeLRU(entry);
+ }
+}
diff --git a/impl/src/main/java/org/apache/myfaces/flow/cdi/DefaultCDIFacesFlowProvider.java b/impl/src/main/java/org/apache/myfaces/flow/cdi/DefaultCDIFacesFlowProvider.java
index 525b505..3d892e9 100644
--- a/impl/src/main/java/org/apache/myfaces/flow/cdi/DefaultCDIFacesFlowProvider.java
+++ b/impl/src/main/java/org/apache/myfaces/flow/cdi/DefaultCDIFacesFlowProvider.java
@@ -111,6 +111,26 @@
}
return null;
}
+
+ @Override
+ public void refreshClientWindow(FacesContext facesContext)
+ {
+ if (!facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
+ {
+ Flow flow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+ if (flow != null)
+ {
+ BeanManager beanManager = getBeanManager(facesContext);
+ if (beanManager != null)
+ {
+ FlowScopeBeanHolder beanHolder = CDIUtils.lookup(beanManager, FlowScopeBeanHolder.class);
+
+ //Refresh client window for flow scope
+ beanHolder.refreshClientWindow(facesContext);
+ }
+ }
+ }
+ }
public BeanManager getBeanManager()
{
diff --git a/impl/src/main/java/org/apache/myfaces/flow/cdi/FacesFlowClientWindowCollection.java b/impl/src/main/java/org/apache/myfaces/flow/cdi/FacesFlowClientWindowCollection.java
new file mode 100644
index 0000000..055feb7
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/flow/cdi/FacesFlowClientWindowCollection.java
@@ -0,0 +1,64 @@
+/*
+ * 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.flow.cdi;
+
+import java.io.Serializable;
+
+/**
+ * This class is a wrapper used to deal with concurrency issues when accessing the inner LRUMap.
+ */
+class FacesFlowClientWindowCollection implements Serializable
+{
+ private ClientWindowFacesFlowLRUMap lruMap;
+
+ public FacesFlowClientWindowCollection(ClientWindowFacesFlowLRUMap lruMap)
+ {
+ this.lruMap = lruMap;
+ }
+
+ public FacesFlowClientWindowCollection()
+ {
+ }
+
+ 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();
+ }
+
+ public void setFlowScopeBeanHolder(FlowScopeBeanHolder holder)
+ {
+ lruMap.setFlowScopeBeanHolder(holder);
+ }
+
+}
diff --git a/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopeBeanHolder.java b/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopeBeanHolder.java
index 052075f..dab87f46 100644
--- a/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopeBeanHolder.java
+++ b/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopeBeanHolder.java
@@ -44,6 +44,7 @@
import org.apache.myfaces.context.servlet.StartupFacesContextImpl;
import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
import org.apache.myfaces.flow.FlowReference;
+import org.apache.myfaces.shared.config.MyfacesConfig;
import org.apache.myfaces.shared.context.ExceptionHandlerImpl;
@@ -67,6 +68,8 @@
private Map<String, List<String>> activeFlowMapKeys = new ConcurrentHashMap<String, List<String>>();
+ private FacesFlowClientWindowCollection windowCollection = null;
+
public static final String CURRENT_FLOW_SCOPE_MAP = "oam.CURRENT_FLOW_SCOPE_MAP";
private static final String FLOW_SCOPE_PREFIX = "oam.flow.SCOPE";
@@ -84,6 +87,7 @@
public void init()
{
FacesContext facesContext = FacesContext.getCurrentInstance();
+ this.refreshClientWindow(facesContext);
facesContext.getExternalContext().getSessionMap().put(FLOW_SCOPE_PREFIX_KEY,
1);
}
@@ -237,6 +241,38 @@
}
}
+ public void refreshClientWindow(FacesContext facesContext)
+ {
+ if (windowCollection == null)
+ {
+ Integer ft = MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).
+ getNumberOfFacesFlowClientWindowIdsInSession();
+ windowCollection = new FacesFlowClientWindowCollection(new ClientWindowFacesFlowLRUMap(ft));
+ }
+ ClientWindow cw = facesContext.getExternalContext().getClientWindow();
+ if (cw != null && cw.getId() != null)
+ {
+ windowCollection.setFlowScopeBeanHolder(this);
+ windowCollection.put(cw.getId(), "");
+ }
+ }
+
+ public void clearFlowMap(String clientWindowId)
+ {
+ List<String> activeFlowKeys = activeFlowMapKeys.remove(clientWindowId);
+ if (activeFlowKeys != null && !activeFlowKeys.isEmpty())
+ {
+ for (String flowMapKey : activeFlowKeys)
+ {
+ ContextualStorage contextualStorage = storageMap.remove(flowMapKey);
+ if (contextualStorage != null)
+ {
+ FlowScopedContextImpl.destroyAllActive(contextualStorage);
+ }
+ }
+ }
+ }
+
public List<String> getActiveFlowMapKeys(FacesContext facesContext)
{
ClientWindow cw = facesContext.getExternalContext().getClientWindow();
@@ -290,6 +326,7 @@
}
activeFlowKeys.add(0, flowMapKey);
activeFlowMapKeys.put(baseKey, activeFlowKeys);
+ refreshClientWindow(facesContext);
}
public void destroyCurrentFlowScope(FacesContext facesContext)
diff --git a/impl/src/main/java/org/apache/myfaces/lifecycle/RestoreViewExecutor.java b/impl/src/main/java/org/apache/myfaces/lifecycle/RestoreViewExecutor.java
index 30dbb2c..4c31513 100644
--- a/impl/src/main/java/org/apache/myfaces/lifecycle/RestoreViewExecutor.java
+++ b/impl/src/main/java/org/apache/myfaces/lifecycle/RestoreViewExecutor.java
@@ -39,6 +39,7 @@
import javax.faces.event.PhaseId;
import javax.faces.event.PostAddToViewEvent;
import javax.faces.flow.FlowHandler;
+import javax.faces.lifecycle.ClientWindow;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.faces.render.RenderKit;
@@ -48,6 +49,7 @@
import javax.faces.view.ViewMetadata;
import javax.faces.webapp.FacesServlet;
import javax.servlet.http.HttpServletResponse;
+import org.apache.myfaces.event.PostClientWindowAndViewInitializedEvent;
import org.apache.myfaces.renderkit.ErrorPageWriter;
import org.apache.myfaces.shared.config.MyfacesConfig;
@@ -200,6 +202,16 @@
// Restore binding
// See https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=806
restoreViewSupport.processComponentBinding(facesContext, viewRoot);
+
+ ClientWindow clientWindow = facesContext.getExternalContext().getClientWindow();
+ if (clientWindow != null)
+ {
+ // The idea of this event is once the client window and the view is initialized,
+ // you have the information required to clean up any scope that belongs to old
+ // clientWindow instances like flow scope (in server side state saving).
+ facesContext.getApplication().publishEvent(facesContext, PostClientWindowAndViewInitializedEvent.class,
+ clientWindow);
+ }
}
else
{ // If the request is a non-postback
@@ -292,6 +304,13 @@
// Store the new UIViewRoot instance in the FacesContext.
facesContext.setViewRoot(viewRoot);
+
+ ClientWindow clientWindow = facesContext.getExternalContext().getClientWindow();
+ if (clientWindow != null)
+ {
+ facesContext.getApplication().publishEvent(facesContext, PostClientWindowAndViewInitializedEvent.class,
+ clientWindow);
+ }
FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
if (flowHandler != null)
diff --git a/impl/src/main/java/org/apache/myfaces/spi/FacesFlowProvider.java b/impl/src/main/java/org/apache/myfaces/spi/FacesFlowProvider.java
index 3640e72..0884027 100644
--- a/impl/src/main/java/org/apache/myfaces/spi/FacesFlowProvider.java
+++ b/impl/src/main/java/org/apache/myfaces/spi/FacesFlowProvider.java
@@ -36,5 +36,8 @@
public abstract void doBeforeExitFlow(FacesContext context, Flow flow);
public abstract Map<Object, Object> getCurrentFlowScope(FacesContext context);
-
+
+ public void refreshClientWindow(FacesContext context)
+ {
+ }
}
diff --git a/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java b/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java
index d1eb2bd..508d6b3 100755
--- a/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java
+++ b/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java
@@ -514,14 +514,30 @@
/**
* 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
+ * javax.faces.CLIENT_WINDOW_MODE is enabled and javax.faces.STATE_SAVING_METHOD is set
+ * to "server". 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";
+ static final String INIT_PARAM_NUMBER_OF_FLASH_TOKENS_IN_SESSION =
+ "org.apache.myfaces.NUMBER_OF_FLASH_TOKENS_IN_SESSION";
+
+ /**
+ * Indicate the max number of client window ids stored into session by faces flow. It is only active when
+ * javax.faces.CLIENT_WINDOW_MODE is enabled and javax.faces.STATE_SAVING_METHOD is set
+ * to "server". This param is related to the limit of active client
+ * windows per session, and it is used to cleanup flow scope beans when a client window or view becomes
+ * invalid.
+ * 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 INIT_PARAM_NUMBER_OF_FACES_FLOW_CLIENT_WINDOW_IDS_IN_SESSION =
+ "org.apache.myfaces.FACES_FLOW_CLIENT_WINDOW_IDS_IN_SESSION";
private boolean _prettyHtml;
private boolean _detectJavascript;
@@ -564,6 +580,7 @@
private Integer _numberOfViewsInSession;
private Integer _numberOfSequentialViewsInSession;
private Integer _numberOfFlashTokensInSession;
+ private Integer _numberOfFacesFlowClientWindowIdsInSession;
private static final boolean TOMAHAWK_AVAILABLE;
private static final boolean MYFACES_IMPL_AVAILABLE;
@@ -866,7 +883,11 @@
}
myfacesConfig.setNumberOfFlashTokensInSession(WebConfigParamUtils.getIntegerInitParameter(
extCtx,
- INIT_PARAM_NUMBER_OF_VIEWS_IN_SESSION, numberOfFlashTokensInSessionDefault));
+ INIT_PARAM_NUMBER_OF_FLASH_TOKENS_IN_SESSION, numberOfFlashTokensInSessionDefault));
+ myfacesConfig.setNumberOfFacesFlowClientWindowIdsInSession(WebConfigParamUtils.getIntegerInitParameter(
+ extCtx,
+ INIT_PARAM_NUMBER_OF_FACES_FLOW_CLIENT_WINDOW_IDS_IN_SESSION,
+ numberOfFlashTokensInSessionDefault));
if (TOMAHAWK_AVAILABLE)
{
@@ -1503,4 +1524,20 @@
{
this._numberOfFlashTokensInSession = numberOfFlashTokensInSession;
}
+
+ /**
+ * @return the _numberOfFacesFlowClientWindowIdsInSession
+ */
+ public Integer getNumberOfFacesFlowClientWindowIdsInSession()
+ {
+ return _numberOfFacesFlowClientWindowIdsInSession;
+ }
+
+ /**
+ * @param _numberOfFacesFlowClientWindowIdsInSession the _numberOfFacesFlowClientWindowIdsInSession to set
+ */
+ public void setNumberOfFacesFlowClientWindowIdsInSession(Integer numberOfFacesFlowClientWindowIdsInSession)
+ {
+ this._numberOfFacesFlowClientWindowIdsInSession = numberOfFacesFlowClientWindowIdsInSession;
+ }
}
diff --git a/shared/src/main/java/org/apache/myfaces/shared/context/flash/ClientWindowFlashTokenLRUMap.java b/shared/src/main/java/org/apache/myfaces/shared/context/flash/ClientWindowFlashTokenLRUMap.java
index 29ceaaf..008bb08 100644
--- a/shared/src/main/java/org/apache/myfaces/shared/context/flash/ClientWindowFlashTokenLRUMap.java
+++ b/shared/src/main/java/org/apache/myfaces/shared/context/flash/ClientWindowFlashTokenLRUMap.java
@@ -66,11 +66,6 @@
super(map, scanUntilRemovable);
}
- public synchronized String getValue(String key)
- {
- return (String) get(key);
- }
-
@Override
protected boolean removeLRU(LinkEntry entry)
{
diff --git a/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java b/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java
index 20105ac..6cc263a 100644
--- a/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java
+++ b/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java
@@ -749,14 +749,24 @@
* On the next request we can get it with _getRenderFlashMapTokenFromPreviousRequest().
* @param externalContext
*/
- private void _saveRenderFlashMapTokenForNextRequest(ExternalContext externalContext)
+ private void _saveRenderFlashMapTokenForNextRequest(FacesContext facesContext)
{
+ ExternalContext externalContext = facesContext.getExternalContext();
String tokenValue = (String) externalContext.getRequestMap().get(FLASH_RENDER_MAP_TOKEN);
ClientWindow clientWindow = externalContext.getClientWindow();
if (clientWindow != null)
{
- FlashClientWindowTokenCollection lruMap = getFlashClientWindowTokenCollection(externalContext, true);
- lruMap.put(clientWindow.getId(), tokenValue);
+ if (facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
+ {
+ //Use HttpSession or PortletSession object
+ Map<String, Object> sessionMap = externalContext.getSessionMap();
+ sessionMap.put(FLASH_RENDER_MAP_TOKEN+SEPARATOR_CHAR+clientWindow.getId(), tokenValue);
+ }
+ else
+ {
+ FlashClientWindowTokenCollection lruMap = getFlashClientWindowTokenCollection(externalContext, true);
+ lruMap.put(clientWindow.getId(), tokenValue);
+ }
}
else
{
@@ -783,16 +793,26 @@
* @param externalContext
* @return
*/
- private String _getRenderFlashMapTokenFromPreviousRequest(ExternalContext externalContext)
+ private String _getRenderFlashMapTokenFromPreviousRequest(FacesContext facesContext)
{
+ ExternalContext externalContext = facesContext.getExternalContext();
String tokenValue = null;
ClientWindow clientWindow = externalContext.getClientWindow();
if (clientWindow != null)
{
- FlashClientWindowTokenCollection lruMap = getFlashClientWindowTokenCollection(externalContext, false);
- if (lruMap != null)
+ if (facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
{
- tokenValue = (String) lruMap.get(clientWindow.getId());
+ Map<String, Object> sessionMap = externalContext.getSessionMap();
+ tokenValue = (String) sessionMap.get(FLASH_RENDER_MAP_TOKEN+
+ SEPARATOR_CHAR+clientWindow.getId());
+ }
+ else
+ {
+ FlashClientWindowTokenCollection lruMap = getFlashClientWindowTokenCollection(externalContext, false);
+ if (lruMap != null)
+ {
+ tokenValue = (String) lruMap.get(clientWindow.getId());
+ }
}
}
else
@@ -830,7 +850,7 @@
Map<String, Object> requestMap = externalContext.getRequestMap();
final String previousRenderToken
- = _getRenderFlashMapTokenFromPreviousRequest(externalContext);
+ = _getRenderFlashMapTokenFromPreviousRequest(facesContext);
if (previousRenderToken != null)
{
// "restore" the renderMap from the previous request
@@ -868,7 +888,7 @@
// we now have the final render token for this request, thus we can
// already save it for the next request, because it won't change
- _saveRenderFlashMapTokenForNextRequest(externalContext);
+ _saveRenderFlashMapTokenForNextRequest(facesContext);
}
/**
@@ -1071,20 +1091,29 @@
Map<String, Object> map = _getRenderFlashMap(facesContext);
if (map.isEmpty())
{
- // Remove token, because it is not necessary
- FlashClientWindowTokenCollection lruMap = getFlashClientWindowTokenCollection(externalContext, false);
- if (lruMap != null)
+ if (facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext))
{
- lruMap.remove(clientWindow.getId());
Map<String, Object> sessionMap = externalContext.getSessionMap();
- if (lruMap.isEmpty())
+ sessionMap.remove(FLASH_RENDER_MAP_TOKEN+SEPARATOR_CHAR+clientWindow.getId());
+ }
+ else
+ {
+ // Remove token, because it is not necessary
+ FlashClientWindowTokenCollection lruMap = getFlashClientWindowTokenCollection(
+ externalContext, false);
+ if (lruMap != null)
{
- sessionMap.remove(FLASH_CW_LRU_MAP);
- }
- else
- {
- //refresh remove
- sessionMap.put(FLASH_CW_LRU_MAP, lruMap);
+ 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);
+ }
}
}
}
@@ -1117,7 +1146,8 @@
public void clearFlashMap(FacesContext facesContext, String clientWindowId, String token)
{
- if (!_flashScopeDisabled)
+ if ((!_flashScopeDisabled) &&
+ (!facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext)))
{
ExternalContext externalContext = facesContext.getExternalContext();
ClientWindow clientWindow = externalContext.getClientWindow();