You are viewing a plain text version of this content. The canonical link for it is here.
Posted to adffaces-commits@incubator.apache.org by aw...@apache.org on 2006/10/18 00:02:16 UTC
svn commit: r465103 - in
/incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad:
component/UIXCollection.java component/ValueMap.java
render/ClientRowKeyManager.java render/ClientRowKeyManagerFactory.java
Author: awiner
Date: Tue Oct 17 17:02:15 2006
New Revision: 465103
URL: http://svn.apache.org/viewvc?view=rev&rev=465103
Log:
ADFFACES-210: move rowKey string token map from UIXCollection into corresponding Renderer. Patch from Arjuna Wijeyekoon
Added:
incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ClientRowKeyManager.java
incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ClientRowKeyManagerFactory.java
Modified:
incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java
incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/ValueMap.java
Modified: incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java
URL: http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java?view=diff&rev=465103&r1=465102&r2=465103
==============================================================================
--- incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java (original)
+++ incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXCollection.java Tue Oct 17 17:02:15 2006
@@ -16,8 +16,8 @@
package org.apache.myfaces.trinidad.component;
import java.io.IOException;
-
import java.io.Serializable;
+
import java.util.AbstractMap;
import java.util.Collections;
import java.util.List;
@@ -30,11 +30,15 @@
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
+import javax.faces.render.Renderer;
import org.apache.myfaces.trinidad.event.SelectionEvent;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
import org.apache.myfaces.trinidad.model.CollectionModel;
import org.apache.myfaces.trinidad.model.SortCriterion;
+import org.apache.myfaces.trinidad.render.ClientRowKeyManager;
+import org.apache.myfaces.trinidad.render.ClientRowKeyManagerFactory;
+
/**
* Base class for components that do stamping.
@@ -212,8 +216,7 @@
// _stampState is stored as an instance variable, so it isn't
// automatically saved
Object superState = super.saveState(context);
- Object stampState;
- ValueMap<Object> currencyCache;
+ final Object stampState, clientKeyMgr;
// becareful not to create the internal state too early:
// otherwise, the internal state will be shared between
@@ -222,18 +225,16 @@
if (iState != null)
{
stampState = iState._stampState;
- currencyCache = iState._currencyCache;
- if ((currencyCache != null) && currencyCache.isEmpty())
- currencyCache = null;
+ clientKeyMgr = iState._clientKeyMgr;
}
else
{
stampState = null;
- currencyCache = null;
+ clientKeyMgr = null;
}
- if ((superState != null) || (stampState != null) || (currencyCache != null))
- return new Object[]{superState, stampState, currencyCache};
+ if ((superState != null) || (stampState != null) || (clientKeyMgr != null))
+ return new Object[]{superState, stampState, clientKeyMgr};
return null;
}
@@ -242,25 +243,25 @@
@Override
public void restoreState(FacesContext context, Object state)
{
- final Object superState, stampState, currencyCache;
+ final Object superState, stampState, clientKeyMgr;
Object[] array = (Object[]) state;
if (array != null)
{
superState = array[0];
stampState = array[1];
- currencyCache = array[2];
+ clientKeyMgr = array[2];
}
else
{
- superState = stampState = currencyCache = null;
+ superState = stampState = clientKeyMgr = null;
}
super.restoreState(context, superState);
- if ((stampState != null) || (currencyCache != null))
+ if ((stampState != null) || (clientKeyMgr != null))
{
InternalState iState = _getInternalState(true);
iState._stampState = (StampState) stampState;
- iState._currencyCache = (ValueMap<Object>) currencyCache;
+ iState._clientKeyMgr = (ClientRowKeyManager) clientKeyMgr;
}
else
{
@@ -270,7 +271,7 @@
if (iState != null)
{
iState._stampState = null;
- iState._currencyCache = null;
+ iState._clientKeyMgr = null;
}
}
}
@@ -461,10 +462,14 @@
InternalState istate = _getInternalState(true);
// we must not clear the currency cache everytime. only clear
// it in response to specific events: bug 4773659
+
+ // TODO all this code should be removed and moved into the renderer:
if (istate._clearTokenCache)
{
istate._clearTokenCache = false;
- _getCurrencyCache().clear();
+ ClientRowKeyManager keyMgr = getClientRowKeyManager();
+ if (keyMgr instanceof DefaultClientKeyManager)
+ ((DefaultClientKeyManager) keyMgr).clear();
}
_flushCachedModel();
@@ -531,57 +536,13 @@
if (_equals(currencyObject, initKey))
return null;
- String key = _getToken(currencyObject);
+ FacesContext fc = FacesContext.getCurrentInstance();
+ String key = getClientRowKeyManager().getClientRowKey(fc, this, currencyObject);
return key;
}
- private String _getToken(Object rowKey)
- {
- assert rowKey != null;
-
- ValueMap<Object> currencyCache = _getCurrencyCache();
- String key = (String) currencyCache.get(rowKey);
- if (key == null)
- {
- if (rowKey instanceof String)
- {
- // TODO: make sure that this string is suitable for use as
- // NamingContainer ids:
- key = rowKey.toString();
- if (_isOptimizedKey(key))
- {
- // no need to add to the token map:
- return key;
- }
- }
-
- key = _createToken(currencyCache);
- if (_LOG.isFiner())
- _LOG.finer("Storing token:"+key+
- " for rowKey:"+rowKey);
- currencyCache.put(rowKey, key);
- }
- return key;
- }
-
- private boolean _isOptimizedKey(String key)
- {
- // if a key could be a number, then it might conflict with our
- // internal representation of tokens. Therefore, if a key could be
- // a number, then use the token cache.
- // if there is no way this key can be a number, then it can
- // be treated as an optimized key and can bypass the token cache
- // system:
- return ((key.length() > 0) && (!Character.isDigit(key.charAt(0))));
- }
-
- private String _createToken(ValueMap<Object> currencyCache)
- {
- String key = String.valueOf(currencyCache.size());
- return key;
- }
/**
* This is a safe way of getting currency keys and not accidentally forcing
@@ -617,7 +578,7 @@
* the start of the encode phase on the next request.
* <P>
* This method gets the corresponding currencyKey and passes it to
- * {@link #setCurrencyKey}
+ * {@link #setRowKey}
* @see #getCurrencyString
*/
public void setCurrencyString(String currency)
@@ -628,15 +589,15 @@
return;
}
- Object currencyObject = _isOptimizedKey(currency)
- ? currency
- : _getCurrencyCache().getKey(currency);
- if (currencyObject == null)
+ FacesContext fc = FacesContext.getCurrentInstance();
+ Object rowkey = getClientRowKeyManager().getRowKey(fc, this, currency);
+
+ if (rowkey == null)
{
_LOG.severe("Could not restore currency for currencyString:"+currency);
}
else
- setRowKey(currencyObject);
+ setRowKey(rowkey);
}
/**
@@ -883,6 +844,23 @@
return getCollectionModel(true);
}
+ public final ClientRowKeyManager getClientRowKeyManager()
+ {
+ // this method must be public, because specific renderers
+ // need access to the ClientRowKeyManager so that they might prune it.
+
+ InternalState iState = _getInternalState(true);
+ if (iState._clientKeyMgr == null)
+ {
+ FacesContext fc = FacesContext.getCurrentInstance();
+ Renderer r = getRenderer(fc);
+ iState._clientKeyMgr = (r instanceof ClientRowKeyManagerFactory)
+ ? ((ClientRowKeyManagerFactory) r).createClientRowKeyManager(fc, this)
+ : new DefaultClientKeyManager();
+ }
+ return iState._clientKeyMgr;
+ }
+
/**
* Gets the CollectionModel to use with this component.
*
@@ -1129,14 +1107,6 @@
return iState._stampState;
}
- private ValueMap<Object> _getCurrencyCache()
- {
- InternalState iState = _getInternalState(true);
- if (iState._currencyCache == null)
- iState._currencyCache = new ValueMap<Object>();
- return iState._currencyCache;
- }
-
/**
* sets an EL variable.
* @param varName the name of the variable
@@ -1172,6 +1142,84 @@
return component.getFacets().size();
}
+ private static final class DefaultClientKeyManager extends ClientRowKeyManager
+ {
+
+ public void clear()
+ {
+ _currencyCache.clear();
+ }
+
+ public Object getRowKey(FacesContext context, UIComponent component, String clientRowKey)
+ {
+ if (_isOptimizedKey(clientRowKey))
+ return clientRowKey;
+
+ ValueMap<Object,String> currencyCache = _currencyCache;
+ Object rowkey = currencyCache.getKey(clientRowKey);
+ return rowkey;
+ }
+
+ public String getClientRowKey(FacesContext context, UIComponent component, Object rowKey)
+ {
+ assert rowKey != null;
+
+ ValueMap<Object,String> currencyCache = _currencyCache;
+ String key = currencyCache.get(rowKey);
+ // check to see if we already have a string key:
+ if (key == null)
+ {
+ // we don't have a string-key, so create a new one.
+
+ // first check to see if the rowkey itself can be used as the string-key:
+ if (rowKey instanceof String)
+ {
+ // TODO: make sure that this string is suitable for use as
+ // NamingContainer ids:
+ key = rowKey.toString();
+ if (_isOptimizedKey(key))
+ {
+ // no need to add to the token map:
+ return key;
+ }
+ }
+
+ key = _createToken(currencyCache);
+
+ if (_LOG.isFiner())
+ _LOG.finer("Storing token:"+key+
+ " for rowKey:"+rowKey);
+
+ currencyCache.put(rowKey, key);
+ }
+ return key;
+ }
+
+ private static boolean _isOptimizedKey(String key)
+ {
+ // if a key could be a number, then it might conflict with our
+ // internal representation of tokens. Therefore, if a key could be
+ // a number, then use the token cache.
+ // if there is no way this key can be a number, then it can
+ // be treated as an optimized key and can bypass the token cache
+ // system:
+ return ((key.length() > 0) && (!Character.isDigit(key.charAt(0))));
+ }
+
+ private static String _createToken(ValueMap<Object,String> currencyCache)
+ {
+ String key = String.valueOf(currencyCache.size());
+ return key;
+ }
+
+ private ValueMap<Object,String> _currencyCache = new ValueMap<Object,String>();
+ }
+
+ // this component's internal state is stored in an inner class
+ // rather than in individual fields, because we want to make it
+ // easy to quickly suck out or restore its internal state,
+ // when this component is itself used as a stamp inside some other
+ // stamping container, eg: nested tables.
private static final class InternalState implements Serializable
{
private transient boolean _hasEvent = false;
@@ -1190,8 +1238,8 @@
// this is the rowKey used to retrieve the default stamp-state for all rows:
private transient Object _initialStampStateKey = _NULL;
+ private ClientRowKeyManager _clientKeyMgr = null;
private StampState _stampState = null;
- private ValueMap<Object> _currencyCache = null;
}
// do not assign a non-null value. values should be assigned lazily. this is
Modified: incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/ValueMap.java
URL: http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/ValueMap.java?view=diff&rev=465103&r1=465102&r2=465103
==============================================================================
--- incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/ValueMap.java (original)
+++ incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/ValueMap.java Tue Oct 17 17:02:15 2006
@@ -34,18 +34,25 @@
*
* @author The Oracle ADF Faces Team
*/
-final class ValueMap<T> extends AbstractMap<T, T> implements Externalizable
+final class ValueMap<K, V> extends AbstractMap<K, V> implements Externalizable
{
public ValueMap()
{
- // noarg constructor needed for serialization
+ // noarg constructor needed by the Externalizable interface
+ this(13);
+ }
+
+ public ValueMap(int initialCapacity)
+ {
+ _cache = new HashMap<K, V>(initialCapacity);
+ _valueMap = new HashMap<V, K>(initialCapacity);
}
/**
* Gets the value associated with the given key
*/
@Override
- public T get(Object key)
+ public V get(Object key)
{
return _cache.get(key);
}
@@ -53,19 +60,19 @@
/**
* Gets the key associated with the given value
*/
- public Object getKey(Object value)
+ public K getKey(V value)
{
return _valueMap.get(value);
}
@Override
- public T put(T key, T value)
+ public V put(K key, V value)
{
- T oldKey = _valueMap.put(value, key);
+ K oldKey = _valueMap.put(value, key);
assert oldKey == null : "value:"+value+" is referenced by both key:"+key+
" and key:"+oldKey;
- T old = _cache.put(key, value);
+ V old = _cache.put(key, value);
assert old == null : "can't put the same key twice";
return old;
}
@@ -84,17 +91,17 @@
}
@Override
- public Set<Map.Entry<T, T>> entrySet()
+ public Set<Map.Entry<K, V>> entrySet()
{
return Collections.unmodifiableSet(_cache.entrySet());
}
- private static <T> Map<T, T> _setupValueMap(Map<T, T> cache)
+ private static <K,V> Map<V, K> _invertMap(Map<K, V> cache)
{
- Map<T, T> valueMap = new HashMap<T, T>(cache.size());
- for(Map.Entry<T, T> entry : cache.entrySet())
+ Map<V, K> valueMap = new HashMap<V, K>(cache.size());
+ for(Map.Entry<K, V> entry : cache.entrySet())
{
- T old = valueMap.put(entry.getValue(), entry.getKey());
+ K old = valueMap.put(entry.getValue(), entry.getKey());
assert old == null : "the value:"+entry.getValue()+
" was bound to both key:"+old+
" and key:"+entry.getKey();
@@ -105,18 +112,24 @@
public void writeExternal(ObjectOutput out) throws IOException
{
- out.writeObject(_cache);
+ if (_cache.isEmpty())
+ out.writeObject(null);
+ else
+ out.writeObject(_cache);
}
- @SuppressWarnings("unchecked")
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
- _cache = (Map<T, T>) in.readObject();
- _valueMap = _setupValueMap(_cache);
+ Map<K, V> cache = (Map<K, V>) in.readObject();
+ if (cache != null)
+ {
+ _cache = cache;
+ _valueMap = _invertMap(_cache);
+ }
}
- private Map<T, T> _cache = new HashMap<T, T>(13);
- private transient Map<T, T> _valueMap = new HashMap<T, T>(13);
+ private Map<K, V> _cache;
+ private transient Map<V, K> _valueMap;
//private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(InvertibleMap.class);
}
Added: incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ClientRowKeyManager.java
URL: http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ClientRowKeyManager.java?view=auto&rev=465103
==============================================================================
--- incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ClientRowKeyManager.java (added)
+++ incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ClientRowKeyManager.java Tue Oct 17 17:02:15 2006
@@ -0,0 +1,37 @@
+package org.apache.myfaces.trinidad.render;
+
+import java.io.Serializable;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+/**
+ * This class manages server-side
+ * rowkey Objects with client-side string keys.
+ * This class must be Serializable as it is state-saved along with the
+ * UIComponent state.
+ */
+public abstract class ClientRowKeyManager implements Serializable
+{
+ /**
+ * Gets a string version of a key that identifies the row with the given rowkey.
+ * This string key can be used on the client-side to identify the row.
+ * If a string key for the given rowkey does not exist, then a new one is
+ * created. The lifespan of this string rowkey is entirely upto each
+ * implementation. Implementors must ensure that if a particular row is still
+ * present on the client-side, then its string key must also continue to be valid.
+ * @param rowKey the rowkey to convert into a client key. Note that
+ * null is special and is not allowed.
+ */
+ public abstract String getClientRowKey(FacesContext context, UIComponent component, Object rowKey);
+
+ /**
+ * Gets the corresponding server-side rowkey object from the given client-side string
+ * key. If the string key has expired, implementors should return null. However,
+ * if any part of a row is still present on the client-side, its corresponding
+ * string-key may not expire.
+ * @param clientRowKey the string key
+ * @return null, if the string key has expired, or never existed.
+ */
+ public abstract Object getRowKey(FacesContext context, UIComponent component, String clientRowKey);
+}
Added: incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ClientRowKeyManagerFactory.java
URL: http://svn.apache.org/viewvc/incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ClientRowKeyManagerFactory.java?view=auto&rev=465103
==============================================================================
--- incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ClientRowKeyManagerFactory.java (added)
+++ incubator/adffaces/trunk/trinidad/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ClientRowKeyManagerFactory.java Tue Oct 17 17:02:15 2006
@@ -0,0 +1,22 @@
+package org.apache.myfaces.trinidad.render;
+
+import javax.faces.component.UIComponent;
+
+import javax.faces.context.FacesContext;
+
+
+/**
+ * A producer of ClientRowKeyManagers.
+ * Typically this interface will be implemented by Renderers of stamping
+ * components (like UIXCollection subclasses) that need to provide
+ * string-row-keys that can be used to identify data rows on the client.
+ */
+public interface ClientRowKeyManagerFactory
+{
+ /**
+ * Create a new ClientRowKeyManager for the given UIComponent
+ */
+ public ClientRowKeyManager createClientRowKeyManager(
+ FacesContext context,
+ UIComponent component);
+}