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/04/14 03:30:40 UTC
svn commit: r1091984 -
/myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/RowKeySetAttributeChange.java
Author: bsullivan
Date: Thu Apr 14 01:30:40 2011
New Revision: 1091984
URL: http://svn.apache.org/viewvc?rev=1091984&view=rev
Log:
TRINIDAD-2074 RowKeySetAttributeChange doesn't check if oldValue is non-null and a RowKeySet before casting and dereferencing
Modified:
myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/RowKeySetAttributeChange.java
Modified: 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=1091984&r1=1091983&r2=1091984&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/RowKeySetAttributeChange.java (original)
+++ myfaces/trinidad/trunk/trinidad-api/src/main/java/org/apache/myfaces/trinidad/change/RowKeySetAttributeChange.java Thu Apr 14 01:30:40 2011
@@ -1,21 +1,3 @@
-/*
- * 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.trinidad.change;
import java.util.Map;
@@ -31,7 +13,15 @@ import org.apache.myfaces.trinidad.model
/**
* Handles RowKeySetAttribute changes, which need to be handled specially because they are mutable
- * and programmers assume that the instances don't change
+ * and programmers assume that the instances don't change.
+ *
+ * Cases that we need to worry about:
+ * 1) old value is null
+ * 2) new value is null (should clear existing RowKeySet if possible)
+ * 3) old value = new value
+ * 4) new value is a ValueExpression or ValueBinding
+ * 5) old value is a ValueExpression that needs to be evaluated in context
+ * 6) RowKeySet is internally bound to a model that needs to be evaluated in context
*/
public final class RowKeySetAttributeChange extends AttributeComponentChange
{
@@ -47,144 +37,112 @@ public final class RowKeySetAttributeCha
@Override
@SuppressWarnings("deprecation")
- public void changeComponent(UIComponent uiComponent)
+ public void changeComponent(UIComponent component)
{
- Map<String, Object> attributeMap = uiComponent.getAttributes();
+ Map<String, Object> attributeMap = component.getAttributes();
- Object attributeValue = getAttributeValue();
- String attributeName = getAttributeName();
+ Object newAttributeValue = getAttributeValue();
+ String attrName = 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)
+ if ((newAttributeValue instanceof RowKeySet) || (newAttributeValue == null))
{
- uiComponent.setValueExpression(attributeName, (ValueExpression)attributeValue);
- attributeMap.remove(attributeName);
+ // 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
+ _updateRowKeySetInPlace(component, attrName, (RowKeySet)newAttributeValue);
}
- else if (attributeValue instanceof ValueBinding)
+ else if (newAttributeValue instanceof ValueExpression)
{
- uiComponent.setValueBinding(attributeName, (ValueBinding)attributeValue);
- attributeMap.remove(attributeName);
+ // if the new attribute value is a ValueExpession, set it and remove the old value
+ // so that the ValueExpression takes precedence
+ component.setValueExpression(attrName, (ValueExpression)newAttributeValue);
+ attributeMap.remove(attrName);
+ }
+ else if (newAttributeValue instanceof ValueBinding)
+ {
+ // if the new attribute value is a ValueBinding, set it and remove the old value
+ // so that the ValueBinding takes precedence
+ component.setValueBinding(attrName, (ValueBinding)newAttributeValue);
+ attributeMap.remove(attrName);
}
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);
- final FacesContext context = FacesContext.getCurrentInstance();
-
- if (expression != null)
- {
- //use EL to get the oldValue and then determine whether we need to update in place
- context.getViewRoot().invokeOnComponent(
- context,
- _clientId,
- new GetOldValueAndUpdate(expression, (RowKeySet)attributeValue));
- }
- else
- {
- context.getViewRoot().invokeOnComponent(context, _clientId,
- new GetOldValueAndUpdate(attributeName, (RowKeySet)attributeValue));
-
- }
- }
-
- attributeMap.put(attributeName, attributeValue);
+ {
+ // perform the default behavior
+ attributeMap.put(attrName, newAttributeValue);
}
}
-
- private static void _updateKeySet(String clientId, RowKeySet oldKeySet, RowKeySet newKeySet)
+
+ private void _updateRowKeySetInPlace(UIComponent component, String attrName, RowKeySet newValue)
{
- // 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));
- }
- }
+ ValueExpression oldExpression = component.getValueExpression(attrName);
+
+ // due to bug in how the trinidad table and tree handle their RowKeySets, always use
+ // invoke on component and get the old value in context all of the time for now rather
+ // than trying to get the value directly if we don't have an expression
+ //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(oldExpression, attrName, newValue));
}
-
+
/**
* Get the oldValue in context and update it in context
*/
private static final class GetOldValueAndUpdate implements ContextCallback
{
- public GetOldValueAndUpdate(ValueExpression expression, RowKeySet newKeySet)
+ public GetOldValueAndUpdate(ValueExpression expression, String attributeName, RowKeySet newKeySet)
{
- _attributeName = null;
_expression = expression;
- _newKeySet = newKeySet;
- }
- public GetOldValueAndUpdate(String attributeName, RowKeySet newKeySet)
- {
- _expression = null;
_attributeName = attributeName;
_newKeySet = newKeySet;
}
-
+
public void invokeContextCallback(FacesContext context,
UIComponent target)
{
+ Object oldValue;
+
+ // due to bug in how tables and trees handle RowKeySet, temporarily support getting the
+ // old value in context, even when we don't have a value expression
if (_expression != null)
- {
- // update the KeySet with the old and new values
- RowKeySetAttributeChange._updateKeySet(null,
- (RowKeySet)_expression.getValue(context.getELContext()),
- _newKeySet);
- }
- else
- {
- Map<String, Object> attributeMap = target.getAttributes();
- RowKeySet oldKeySet = (RowKeySet) attributeMap.get(_attributeName);
-
- // update the KeySet with the old and new values
- RowKeySetAttributeChange._updateKeySet(null,
- oldKeySet,
- _newKeySet);
- }
- }
-
- private final ValueExpression _expression;
- private final String _attributeName;
- 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;
+ oldValue = _expression.getValue(context.getELContext());
+ else
+ oldValue = target.getAttributes().get(_attributeName);
+
+ // update the old KeySet with the old and new values
+ _updateKeySet(target, oldValue);
}
- public void invokeContextCallback(FacesContext context,
- UIComponent target)
+ private void _updateKeySet(UIComponent component, Object oldValue)
{
- _oldKeySet.clear();
- _oldKeySet.addAll(_newKeySet);
+ // check for equality because otherwise we would clear ourselves and end up empty
+ if (oldValue != _newKeySet)
+ {
+ // if the old value is a RowKeySet, we can replace in place
+ if (oldValue instanceof RowKeySet)
+ {
+ RowKeySet oldKeySet = (RowKeySet)oldValue;
+
+ oldKeySet.clear();
+
+ if (_newKeySet != null)
+ {
+ oldKeySet.addAll(_newKeySet);
+ }
+ }
+ else
+ {
+ // if the oldKeySet is null, just set the new keySet
+ component.getAttributes().put(_attributeName, _newKeySet);
+ }
+ }
}
- private final RowKeySet _oldKeySet;
+ private final ValueExpression _expression;
+ private final String _attributeName;
private final RowKeySet _newKeySet;
}