You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by bs...@apache.org on 2011/01/19 01:55:17 UTC
svn commit: r1060640 - in
/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad:
change/RowKeySetAttributeChange.java component/UIXComponentBase.java
Author: bsullivan
Date: Wed Jan 19 00:55:17 2011
New Revision: 1060640
URL: http://svn.apache.org/viewvc?rev=1060640&view=rev
Log:
Trinidad-2011 RowKeySet Attribute Changes surprisingly change object identity
Fix by special casing RowKeySet changes
Added:
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/RowKeySetAttributeChange.java (with props)
Modified:
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
Added: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/RowKeySetAttributeChange.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/RowKeySetAttributeChange.java?rev=1060640&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/RowKeySetAttributeChange.java (added)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/RowKeySetAttributeChange.java Wed Jan 19 00:55:17 2011
@@ -0,0 +1,164 @@
+package org.apache.myfaces.trinidad.change;
+
+import java.util.Map;
+
+import javax.el.ValueExpression;
+
+import javax.faces.component.ContextCallback;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.el.ValueBinding;
+
+import org.apache.myfaces.trinidad.model.RowKeySet;
+
+/**
+ * Handles RowKeySetAttribute changes, which need to be handled specially because they are mutable
+ * and programmers assume that the instances don't change
+ */
+public final class RowKeySetAttributeChange extends AttributeComponentChange
+{
+ public RowKeySetAttributeChange(String clientId, String propertyName, Object value)
+ {
+ super(propertyName, value);
+
+ if ((clientId == null) || (clientId.length() == 0))
+ throw new IllegalArgumentException("No clientId specified");
+
+ _clientId = clientId;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public void changeComponent(UIComponent uiComponent)
+ {
+ Map<String, Object> attributeMap = uiComponent.getAttributes();
+
+ Object attributeValue = getAttributeValue();
+ String attributeName = getAttributeName();
+
+ // if the attributevalue is a ValueExpression or ValueBinding, use the
+ // appropriate setValueExpression/setValueBinding call and remove the
+ // current attribute value, if any, so that the ValueExpression/ValueBinding
+ // can take precedence
+ if (attributeValue instanceof ValueExpression)
+ {
+ uiComponent.setValueExpression(attributeName, (ValueExpression)attributeValue);
+ attributeMap.remove(attributeName);
+ }
+ else if (attributeValue instanceof ValueBinding)
+ {
+ uiComponent.setValueBinding(attributeName, (ValueBinding)attributeValue);
+ attributeMap.remove(attributeName);
+ }
+ else
+ {
+ // Specially handle RowKeySet case by replacing the contents of the RowKeySet in-place
+ // rather than replacing the entire object. This keeps the mutable object instance from
+ // changing
+ if (attributeValue instanceof RowKeySet)
+ {
+ ValueExpression expression = uiComponent.getValueExpression(attributeName);
+
+ Object oldValue;
+
+ if (expression != null)
+ {
+ //use EL to get the oldValue and then determine whether we need to update in place
+ final FacesContext context = FacesContext.getCurrentInstance();
+
+ context.getViewRoot().invokeOnComponent(
+ context,
+ _clientId,
+ new GetOldValueAndUpdate(expression, (RowKeySet)attributeValue));
+ }
+ else
+ {
+ oldValue = attributeMap.get(attributeName);
+
+ if (oldValue instanceof RowKeySet)
+ {
+ _updateKeySet(_clientId, (RowKeySet)oldValue, (RowKeySet)attributeValue);
+
+ // we updated in place, but we still need to set the attribute in order for partial
+ // state saving to work
+ }
+ }
+ }
+
+
+ attributeMap.put(attributeName, attributeValue);
+ }
+ }
+
+ private static void _updateKeySet(String clientId, RowKeySet oldKeySet, RowKeySet newKeySet)
+ {
+ // check for equality because otherwise we would clear ourselves and end up empty
+ if (oldKeySet != newKeySet)
+ {
+ // no client id, so we're in context
+ if (clientId == null)
+ {
+ oldKeySet.clear();
+ oldKeySet.addAll(newKeySet);
+ }
+ else
+ {
+ final FacesContext context = FacesContext.getCurrentInstance();
+
+ context.getViewRoot().invokeOnComponent(
+ context,
+ clientId,
+ new RowKeySetUpdater(oldKeySet, newKeySet));
+ }
+ }
+ }
+
+ /**
+ * Get the oldValue in context and update it in context
+ */
+ private static final class GetOldValueAndUpdate implements ContextCallback
+ {
+ public GetOldValueAndUpdate(ValueExpression expression, RowKeySet newKeySet)
+ {
+ _expression = expression;
+ _newKeySet = newKeySet;
+ }
+ public void invokeContextCallback(FacesContext context,
+ UIComponent target)
+ {
+ // update the KeySet with the old and new values
+ RowKeySetAttributeChange._updateKeySet(null,
+ (RowKeySet)_expression.getValue(context.getELContext()),
+ _newKeySet);
+ }
+
+ private final ValueExpression _expression;
+ private final RowKeySet _newKeySet;
+ }
+
+ /**
+ * Makes sure that we clear and add the RowKeySet in context
+ */
+ private static final class RowKeySetUpdater implements ContextCallback
+ {
+ public RowKeySetUpdater(RowKeySet oldKeySet, RowKeySet newKeySet)
+ {
+ _oldKeySet = oldKeySet;
+ _newKeySet = newKeySet;
+ }
+
+ public void invokeContextCallback(FacesContext context,
+ UIComponent target)
+ {
+ _oldKeySet.clear();
+ _oldKeySet.addAll(_newKeySet);
+ }
+
+ private final RowKeySet _oldKeySet;
+ private final RowKeySet _newKeySet;
+ }
+
+ private static final long serialVersionUID = 1L;
+
+ private final String _clientId;
+}
Propchange: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/RowKeySetAttributeChange.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java?rev=1060640&r1=1060639&r2=1060640&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java Wed Jan 19 00:55:17 2011
@@ -70,10 +70,12 @@ import org.apache.myfaces.trinidad.bean.
import org.apache.myfaces.trinidad.bean.util.StateUtils;
import org.apache.myfaces.trinidad.bean.util.ValueMap;
import org.apache.myfaces.trinidad.change.AttributeComponentChange;
+import org.apache.myfaces.trinidad.change.RowKeySetAttributeChange;
import org.apache.myfaces.trinidad.context.RequestContext;
import org.apache.myfaces.trinidad.event.AttributeChangeEvent;
import org.apache.myfaces.trinidad.event.AttributeChangeListener;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.model.RowKeySet;
import org.apache.myfaces.trinidad.render.ExtendedRenderer;
import org.apache.myfaces.trinidad.render.LifecycleRenderer;
import org.apache.myfaces.trinidad.util.CollectionUtils;
@@ -1291,10 +1293,23 @@ abstract public class UIXComponentBase e
String attributeName,
Object attributeValue)
{
- AttributeComponentChange aa =
- new AttributeComponentChange(attributeName, attributeValue);
+ AttributeComponentChange aa;
+
+ FacesContext context = getFacesContext();
+
+ if (attributeValue instanceof RowKeySet)
+ {
+ aa = new RowKeySetAttributeChange(getClientId(context),
+ attributeName,
+ attributeValue);
+ }
+ else
+ {
+ aa = new AttributeComponentChange(attributeName, attributeValue);
+ }
+
RequestContext adfContext = RequestContext.getCurrentInstance();
- adfContext.getChangeManager().addComponentChange(getFacesContext(), this, aa);
+ adfContext.getChangeManager().addComponentChange(context, this, aa);
}
void __rendererDecode(FacesContext context)