You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2008/08/27 09:05:46 UTC
svn commit: r689391 - in
/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal:
application/StateManagerImpl.java util/SubKeyMap.java util/TokenCache.java
Author: matzew
Date: Wed Aug 27 00:05:45 2008
New Revision: 689391
URL: http://svn.apache.org/viewvc?rev=689391&view=rev
Log:
TRINIDAD-1193 - Trinidad StateManagerImpl doesn't clean up UIViewRoot instances when navigating from a page using a GET
ported the original fix to JSF 1.1 trunk
Modified:
myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/SubKeyMap.java
myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java
Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java?rev=689391&r1=689390&r2=689391&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java Wed Aug 27 00:05:45 2008
@@ -242,8 +242,8 @@
// See if we're going to use the application view cache for
// this request
- Map<String, Object> applicationViewCache = null;
- Map<String, Object> perSessionApplicationViewCache = null;
+ Map<String, PageState> applicationViewCache = null;
+ Map<String, PageState> perSessionApplicationViewCache = null;
if (_useApplicationViewCache(context))
{
// OK, we are: so find the application cache and
@@ -256,7 +256,7 @@
{
// If we've already got a copy of the state stored, then
// we just need to make sure it's mirrored on the session
- Object applicationState = applicationViewCache.get(root.getViewId());
+ PageState applicationState = applicationViewCache.get(root.getViewId());
if (applicationState != null)
{
// Note that we've got no work to do...
@@ -284,7 +284,7 @@
assert(cache != null);
// Store bits of the session as subkeys off of the session
- Map<String, Object> stateMap = new SubKeyMap(
+ Map<String, PageState> stateMap = new SubKeyMap<PageState>(
context.getExternalContext().getSessionMap(),
_VIEW_CACHE_KEY + ".");
// Sadly, we can't save just a SerializedView, because we should
@@ -298,6 +298,17 @@
// if this feature has not been disabled
_useViewRootCache(context) ? root : null);
+ // clear out all of the previous PageStates' UIViewRoots and add this page
+ // state as an active page state. This is necessary to avoid UIViewRoots
+ // laying around if the user navigates off of a page using a GET
+ synchronized(this)
+ {
+ if (_activePageState != null)
+ _activePageState.clearViewRootState();
+
+ _activePageState = pageState;
+ }
+
String requestToken = _getRequestTokenForResponse(context);
// If we have a cached token that we want to reuse,
// and that token hasn't disappeared from the cache already
@@ -330,7 +341,7 @@
else
{
// use null viewRoot since this state is shared across users:
- Object applicationState = new PageState(context, structure, state, null);
+ PageState applicationState = new PageState(context, structure, state, null);
// If we need to, stash the state off in our cache
if (!dontSave)
{
@@ -473,8 +484,8 @@
// Load from the application cache
if (_APPLICATION_CACHE_TOKEN.equals(token))
{
- Map<String, Object> cache = _getApplicationViewCache(context);
- Map<String, Object> perSessionCache =
+ Map<String, PageState> cache = _getApplicationViewCache(context);
+ Map<String, PageState> perSessionCache =
_getPerSessionApplicationViewCache(context);
// Synchronize on the application-level cache.
@@ -482,7 +493,7 @@
synchronized (cache)
{
// Look first in the per-session cache
- viewState = (PageState) perSessionCache.get(viewId);
+ viewState = cache.get(viewId);
if (viewState == null)
{
// Nope, it's not there. Look in the application cache
@@ -502,10 +513,10 @@
}
else
{
- Map<String, Object> stateMap = new SubKeyMap(
+ Map<String, PageState> stateMap = new SubKeyMap<PageState>(
context.getExternalContext().getSessionMap(),
_VIEW_CACHE_KEY + ".");
- viewState = (PageState) stateMap.get(token);
+ viewState = stateMap.get(token);
if (viewState != null)
_updateRequestTokenForResponse(context, (String) token);
@@ -693,15 +704,15 @@
// @todo a static size is bad
//
@SuppressWarnings("unchecked")
- static private Map<String, Object> _getApplicationViewCache(FacesContext context)
+ static private Map<String, PageState> _getApplicationViewCache(FacesContext context)
{
synchronized (_APPLICATION_VIEW_CACHE_LOCK)
{
Map<String, Object> appMap = context.getExternalContext().getApplicationMap();
- Map<String, Object> cache = (Map<String, Object>) appMap.get(_APPLICATION_VIEW_CACHE_KEY);
+ Map<String, PageState> cache = (Map<String, PageState>)appMap.get(_APPLICATION_VIEW_CACHE_KEY);
if (cache == null)
{
- cache = new HashMap<String, Object>(128);
+ cache = new HashMap<String, PageState>(128);
appMap.put(_APPLICATION_VIEW_CACHE_KEY, cache);
}
@@ -710,19 +721,19 @@
}
@SuppressWarnings("unchecked")
- static private Map<String, Object> _getPerSessionApplicationViewCache(FacesContext context)
+ static private Map<String, PageState> _getPerSessionApplicationViewCache(FacesContext context)
{
ExternalContext external = context.getExternalContext();
Object session = external.getSession(true);
assert(session != null);
- Map<String, Object> cache;
+ Map<String, PageState> cache;
// Synchronize on the session object to ensure that
// we don't ever create two different caches
synchronized (session)
{
Map<String, Object> sessionMap = external.getSessionMap();
- cache = (Map<String, Object>) sessionMap.get(_APPLICATION_VIEW_CACHE_KEY);
+ cache = (Map<String, PageState>) sessionMap.get(_APPLICATION_VIEW_CACHE_KEY);
if (cache == null)
{
cache = _createPerSessionApplicationViewCache();
@@ -737,9 +748,9 @@
// For the per-session mirror of the application view cache,
// use an LRU LinkedHashMap to store the latest 16 pages.
//
- static private Map<String, Object> _createPerSessionApplicationViewCache()
+ static private Map<String, PageState> _createPerSessionApplicationViewCache()
{
- return new LRUCache<String, Object>(_MAX_PER_SESSION_APPLICATION_SIZE);
+ return new LRUCache<String, PageState>(_MAX_PER_SESSION_APPLICATION_SIZE);
}
static private final int _MAX_PER_SESSION_APPLICATION_SIZE = 16;
@@ -902,25 +913,50 @@
state);
}
+ private static final class ViewRootState
+ {
+ public ViewRootState(FacesContext context, UIViewRoot viewRoot)
+ {
+ if (viewRoot == null)
+ throw new NullPointerException();
+
+ _viewRoot = viewRoot;
+ _viewRootState = viewRoot.saveState(context);
+ }
+
+ public UIViewRoot getViewRoot()
+ {
+ return _viewRoot;
+ }
+
+ public Object getViewRootState()
+ {
+ return _viewRootState;
+ }
+
+ private final UIViewRoot _viewRoot;
+ private final Object _viewRootState;
+ }
+
private static final class PageState implements Serializable
{
private static final long serialVersionUID = 1L;
private final Object _structure, _state;
+
// use transient since UIViewRoots are not Serializable.
- private transient UIViewRoot _root;
- // If the UIViewRoot is lost, then this state is useless, so mark it
- // transient as well:
- private transient Object _viewRootState;
+ private transient ViewRootState _cachedState;
public PageState(FacesContext fc, Object structure, Object state, UIViewRoot root)
{
_structure = structure;
_state = state;
- _root = root;
// we need this state, as we are going to recreate the UIViewRoot later. see
// the popRoot() method:
- _viewRootState = (root != null) ? root.saveState(fc) : null;
+ _cachedState = (root != null)
+ ? new ViewRootState(fc, root)
+ : null;
+
}
public Object getStructure()
@@ -933,6 +969,14 @@
return _state;
}
+ public void clearViewRootState()
+ {
+ synchronized(this)
+ {
+ _cachedState = null;
+ }
+ }
+
@SuppressWarnings("unchecked")
public UIViewRoot popRoot(FacesContext fc)
{
@@ -942,16 +986,15 @@
// which is shared between simultaneous requests from the same user:
synchronized(this)
{
- if (_root != null)
+ if (_cachedState != null)
{
- root = _root;
- viewRootState = _viewRootState;
+ root = _cachedState.getViewRoot();
+ viewRootState = _cachedState.getViewRootState();
// we must clear the cached viewRoot. This is because UIComponent trees
// are mutable and if the back button
// is used to come back to an old PageState, then it would be
// really bad if we reused that component tree:
- _root = null;
- _viewRootState = null;
+ _cachedState = null;
}
}
@@ -1038,7 +1081,7 @@
private Boolean _useViewRootCache;
private Boolean _useApplicationViewCache;
private Boolean _structureGeneratedByTemplate;
-
+ private PageState _activePageState;
private static final int _DEFAULT_CACHE_SIZE = 15;
Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/SubKeyMap.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/SubKeyMap.java?rev=689391&r1=689390&r2=689391&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/SubKeyMap.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/SubKeyMap.java Wed Aug 27 00:05:45 2008
@@ -41,7 +41,7 @@
* "flaw" is actually relied on by PageFlowScopeMap (since it provides
* a handy way to clear out all descendents), so don't "fix" it!
*/
-final public class SubKeyMap extends AbstractMap<String, Object>
+final public class SubKeyMap<V> extends AbstractMap<String, V>
{
public SubKeyMap(Map<String, Object> base, String prefix)
{
@@ -70,25 +70,25 @@
}
@Override
- public Object get(Object key)
+ public V get(Object key)
{
key = _getBaseKey(key);
- return _base.get(key);
+ return (V)_base.get(key);
}
@Override
- public Object put(String key, Object value)
+ public V put(String key, V value)
{
key = _getBaseKey(key);
- return _base.put(key, value);
+ return (V)_base.put(key, value);
}
@Override
- public Object remove(Object key)
+ public V remove(Object key)
{
key = _getBaseKey(key);
_LOG.finest("Removing {0}", key);
- return _base.remove(key);
+ return (V)_base.remove(key);
}
@Override
@@ -101,10 +101,10 @@
}
@Override
- public Set<Map.Entry<String, Object>> entrySet()
+ public Set<Map.Entry<String, V>> entrySet()
{
if (_entrySet == null)
- _entrySet = new Entries();
+ _entrySet = new Entries<V>();
return _entrySet;
}
@@ -131,21 +131,21 @@
//
// Set implementation for SubkeyMap.entrySet()
//
- private class Entries extends AbstractSet<Map.Entry<String, Object>>
+ private class Entries<V> extends AbstractSet<Map.Entry<String, V>>
{
public Entries()
{
}
@Override
- public Iterator<Map.Entry<String, Object>> iterator()
+ public Iterator<Map.Entry<String, V>> iterator()
{
// Sadly, if you just try to use a filtering approach
// on the iterator, you'll get concurrent modification
// exceptions. Consequently, gather the keys in a list
// and iterator over that.
List<String> keyList = _gatherKeys();
- return new EntryIterator(keyList.iterator());
+ return new EntryIterator<V>(keyList.iterator());
}
@Override
@@ -193,7 +193,7 @@
}
}
- private class EntryIterator implements Iterator<Map.Entry<String, Object>>
+ private class EntryIterator<V> implements Iterator<Map.Entry<String, V>>
{
public EntryIterator(Iterator<String> iterator)
{
@@ -205,11 +205,11 @@
return _iterator.hasNext();
}
- public Map.Entry<String, Object> next()
+ public Map.Entry<String, V> next()
{
String baseKey = _iterator.next();
_currentKey = baseKey;
- return new Entry(baseKey);
+ return new Entry<V>(baseKey);
}
public void remove()
@@ -226,7 +226,7 @@
private String _currentKey;
}
- private class Entry implements Map.Entry<String, Object>
+ private class Entry<V> implements Map.Entry<String, V>
{
public Entry(String baseKey)
{
@@ -240,14 +240,14 @@
return _key;
}
- public Object getValue()
+ public V getValue()
{
- return _base.get(_baseKey);
+ return (V)_base.get(_baseKey);
}
- public Object setValue(Object value)
+ public V setValue(V value)
{
- return _base.put(_baseKey, value);
+ return (V)_base.put(_baseKey, value);
}
@SuppressWarnings("unchecked")
@@ -256,7 +256,7 @@
{
if (!(o instanceof Map.Entry))
return false;
- Map.Entry<String, Object> e = (Map.Entry<String, Object>)o;
+ Map.Entry<String, V> e = (Map.Entry<String, V>)o;
return _equals(getKey(), e.getKey()) &&
_equals(getValue(), e.getValue());
}
@@ -283,7 +283,7 @@
private final Map<String, Object> _base;
private final String _prefix;
- private Set<Map.Entry<String, Object>> _entrySet;
+ private Set<Map.Entry<String, V>> _entrySet;
static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(SubKeyMap.class);
}
Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java?rev=689391&r1=689390&r2=689391&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/TokenCache.java Wed Aug 27 00:05:45 2008
@@ -139,9 +139,9 @@
* @param targetStore the map used for storing the value
* @return the token used to store the value
*/
- public String addNewEntry(
- Object value,
- Map<String, Object> targetStore)
+ public <V> String addNewEntry(
+ V value,
+ Map<String, V> targetStore)
{
return addNewEntry(value, targetStore, null);
}
@@ -156,9 +156,9 @@
* will not be freed until this current token is also freed
* @return the token used to store the value
*/
- public String addNewEntry(
- Object value,
- Map<String, Object> targetStore,
+ public <V> String addNewEntry(
+ V value,
+ Map<String, V> targetStore,
String pinnedToken)
{
String remove = null;
@@ -218,11 +218,11 @@
* Remove a token if is ready: there are no pinned references to it.
* Note that it will be absent from the LRUCache.
*/
- synchronized private Object _removeTokenIfReady(
- Map<String, Object> targetStore,
+ synchronized private <V> V _removeTokenIfReady(
+ Map<String, V> targetStore,
String token)
{
- Object removedValue;
+ V removedValue;
// See if it's pinned to something still in memory
if (!_pinned.containsValue(token))
@@ -252,9 +252,9 @@
* Removes a value from the cache.
* @return previous value associated with the token, if any
*/
- public Object removeOldEntry(
+ public <V> V removeOldEntry(
String token,
- Map<String, Object> targetStore)
+ Map<String, V> targetStore)
{
synchronized (this)
{
@@ -269,7 +269,7 @@
/**
* Clear a cache, without resetting the token.
*/
- public void clear(Map<String, Object> targetStore)
+ public <V> void clear(Map<String, V> targetStore)
{
synchronized (this)
{