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)