dev@javaserverfaces.java.net

Re: [280-EZComp] Seeking Retroactive Review

From: Ryan Lubke <Ryan.Lubke_at_Sun.COM>
Date: Tue, 07 Oct 2008 10:43:11 -0700

I've attached an alternate proposal to UIComponent.getAttrs() (or
getValues()).

Comments?



Jacob Hookom wrote:
> then do getValues();
>
> Ryan Lubke wrote:
>> I believe it was called getAttrs() to make the associated EL
>> expressions smaller.
>>
>> #{compositeComponent.attrs} vs #{compositeComponent.attributes}
>>
>> I'm currently experimenting with an ELResolver to alias the name to
>> eliminate the new API.
>>
>>
>>
>> Jacob Hookom wrote:
>>> getAttrs() => getAttributeValues()
>>>
>>> Ed Burns wrote:
>>>> Issue: 280-ComponentResources
>>>>
>>>> To enable <ez:loginPanel action="#{bean.loginAction}" />, where the
>>>> action is re-targeted to be an attribute on an inner component
>>>> inside of
>>>> the composite component, at the discretion of the composite component
>>>> author, I needed to change the special case clause in
>>>> component.getAttributes().get(). Before this change, calling
>>>> component.getAttributes().get() would cause
>>>> any result that is a ValueExpression to have its getValue() called
>>>> before return from component.getAttributes.get() if and only if the
>>>> component was a composite component. This change reverts this
>>>> behavior.
>>>>
>>>> Instead, I've added a new method to UIComponent, getAttrs().
>>>> getAttrs()
>>>> is just like getAttributes() except that its get method *always* will
>>>> cause any results that are ValueExpressions to have their getValue()
>>>> called before return.
>>>>
>>>>
>>>> SECTION: Modified Files
>>>> ----------------------------
>>>> M jsf-api/src/javax/faces/component/UIComponent.java
>>>>
>>>> - add getAttrs()
>>>>
>>>> * <p class="changed_added_2_0">Like {_at_link #getAttributes},
>>>> except
>>>> * that the <code>get()</code> implementation must call
>>>> * <code>getValue()</code> on any result whose type is
>>>> * <code>ValueExpression</code> and return the evaluated result.
>>>> * </p>
>>>>
>>>> M jsf-api/src/javax/faces/component/UIComponentBase.java
>>>>
>>>> - remove special case behavior in getAttributes().get().
>>>>
>>>> M
>>>> jsf-demo/ezcomp00/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> M
>>>> jsf-demo/ezcomp01/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> M
>>>> jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanelTemplate.xhtml
>>>>
>>>> M
>>>> jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> M
>>>> jsf-demo/ezcomp03/src/main/webapp/resources/ezcomp/loginPanelTemplate.xhtml
>>>>
>>>> M
>>>> jsf-demo/ezcomp03/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>>
>>>> - change any expressions that start with
>>>> "#{compositeComponent.attributes"
>>>> to start with "#{compositeComponent.attrs" instead.
>>>>
>>>> SECTION: Diffs
>>>> ----------------------------
>>>> Index: jsf-api/src/javax/faces/component/UIComponent.java
>>>> ===================================================================
>>>> --- jsf-api/src/javax/faces/component/UIComponent.java (revision
>>>> 5480)
>>>> +++ jsf-api/src/javax/faces/component/UIComponent.java (working
>>>> copy)
>>>> -45,6 +45,7 @@
>>>> import java.io.InputStream;
>>>> import java.util.ArrayList;
>>>> import java.util.Arrays;
>>>> +import java.util.Collection;
>>>> import java.util.Collections;
>>>> import java.util.Enumeration;
>>>> import java.util.HashMap;
>>>> -54,6 +55,7 @@
>>>> import java.util.Locale;
>>>> import java.util.Map;
>>>>
>>>> +import java.util.Map.Entry;
>>>> import java.util.MissingResourceException;
>>>> import java.util.PropertyResourceBundle;
>>>> import java.util.ResourceBundle;
>>>> -247,8 +249,86 @@
>>>> * </p>
>>>> */
>>>> public abstract Map<String, Object> getAttributes();
>>>> + + + private transient Map<String, Object>
>>>> valueExpressionEvaluatingAttrsMap;
>>>> + + /** + * <p class="changed_added_2_0">Like {_at_link
>>>> #getAttributes}, except that the + * <code>get()</code>
>>>> implementation must call <code>getValue()</code> on + * any
>>>> result whose type is <code>ValueExpression</code> before returning.
>>>> + * </p>
>>>> + * + * @since 2.0
>>>> + */
>>>> + public Map<String, Object> getAttrs() {
>>>> + + if (null == valueExpressionEvaluatingAttrsMap) {
>>>> + valueExpressionEvaluatingAttrsMap = new Map<String,
>>>> Object>() {
>>>> + + private Map<String, Object> attrs
>>>> = UIComponent.this.getAttributes();
>>>>
>>>> + public void clear() {
>>>> + attrs.clear();
>>>> + }
>>>>
>>>> + public boolean containsKey(Object key) {
>>>> + return attrs.containsKey(key);
>>>> + }
>>>> +
>>>> + public boolean containsValue(Object value) {
>>>> + return attrs.containsValue(value);
>>>> + }
>>>> +
>>>> + public Set<Entry<String, Object>> entrySet() {
>>>> + return attrs.entrySet();
>>>> + }
>>>> +
>>>> + public Object get(Object key) {
>>>> + Object result = attrs.get(key);
>>>> + // check if the result is an expression
>>>> + if (result instanceof ValueExpression) {
>>>> + ValueExpression ve = (ValueExpression)
>>>> result;
>>>> + result =
>>>> ve.getValue(FacesContext.getCurrentInstance().getELContext());
>>>> + }
>>>> + return result;
>>>> + }
>>>> +
>>>> + public boolean isEmpty() {
>>>> + return attrs.isEmpty();
>>>> + }
>>>> +
>>>> + public Set<String> keySet() {
>>>> + return attrs.keySet();
>>>> + }
>>>> +
>>>> + public Object put(String key, Object value) {
>>>> + return attrs.put(key, value);
>>>> + }
>>>> +
>>>> + public void putAll(Map<? extends String, ? extends
>>>> Object> t) {
>>>> + attrs.putAll(t);
>>>> + }
>>>> +
>>>> + public Object remove(Object key) {
>>>> + return attrs.remove(key);
>>>> + }
>>>> +
>>>> + public int size() {
>>>> + return attrs.size();
>>>> + }
>>>> +
>>>> + public Collection<Object> values() {
>>>> + return attrs.values();
>>>> + }
>>>> + + };
>>>> + }
>>>> + + return valueExpressionEvaluatingAttrsMap;
>>>> + }
>>>> +
>>>> +
>>>> //
>>>> ----------------------------------------------------------------
>>>> Bindings
>>>>
>>>>
>>>> Index: jsf-api/src/javax/faces/component/UIComponentBase.java
>>>> ===================================================================
>>>> --- jsf-api/src/javax/faces/component/UIComponentBase.java
>>>> (revision 5480)
>>>> +++ jsf-api/src/javax/faces/component/UIComponentBase.java
>>>> (working copy)
>>>> -1697,16 +1697,7 @@
>>>> }
>>>> } else if (attributes != null) {
>>>> if (attributes.containsKey(key)) {
>>>> - result = (attributes.get(key));
>>>> - // If we have a non-null result and
>>>> - // this is a composite component
>>>> - if (null != result &&
>>>> attributes.containsKey(Resource.COMPONENT_RESOURCE_KEY)) {
>>>> - // check if the result is an expression
>>>> - if (result instanceof ValueExpression) {
>>>> - ValueExpression ve =
>>>> (ValueExpression) result;
>>>> - result =
>>>> ve.getValue(FacesContext.getCurrentInstance().getELContext());
>>>> - }
>>>> - }
>>>> + result = attributes.get(key);
>>>> }
>>>> }
>>>> }
>>>> Index:
>>>> jsf-demo/ezcomp00/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> ===================================================================
>>>> ---
>>>> jsf-demo/ezcomp00/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> (revision 5480)
>>>> +++
>>>> jsf-demo/ezcomp00/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> (working copy)
>>>> -108,7 +108,7 @@
>>>>
>>>> <p>
>>>>
>>>> - <h:commandButton id="loginEvent" value="Login"
>>>> action="#{compositeComponent.attributes.model.loginAction}">
>>>> + <h:commandButton id="loginEvent" value="Login"
>>>> action="#{compositeComponent.attrs.model.loginAction}">
>>>>
>>>> </h:commandButton> Index:
>>>> jsf-demo/ezcomp01/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> ===================================================================
>>>> ---
>>>> jsf-demo/ezcomp01/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> (revision 5480)
>>>> +++
>>>> jsf-demo/ezcomp01/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> (working copy)
>>>> -96,7 +96,7 @@
>>>>
>>>> <p>
>>>>
>>>> - <h:commandButton id="loginEvent" value="Login"
>>>> action="#{compositeComponent.attributes.model.loginAction}">
>>>> + <h:commandButton id="loginEvent" value="Login"
>>>> action="#{compositeComponent.attrs.model.loginAction}">
>>>>
>>>> </h:commandButton> Index:
>>>> jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanelTemplate.xhtml
>>>>
>>>> ===================================================================
>>>> ---
>>>> jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanelTemplate.xhtml
>>>> (revision 5480)
>>>> +++
>>>> jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanelTemplate.xhtml
>>>> (working copy)
>>>> -84,7 +84,7 @@
>>>> <tr><td nowrap="nowrap"><div class="logLbl">
>>>> &nbsp;<span class="LblLev2Txt">
>>>> <label id="sun_label17" for="Login.username" class="LblLev2Txt_sun4">
>>>> -<h:outputText
>>>> value="#{compositeComponent.attributes.usernameLabel}" />
>>>> +<h:outputText value="#{compositeComponent.attrs.usernameLabel}" />
>>>> </label>
>>>> </span></div></td>
>>>>
>>>> -97,7 +97,7 @@
>>>> <tr><td nowrap="nowrap"><div class="logLblLst">
>>>> &nbsp;<span class="LblLev2Txt">
>>>> <label id="sun_label19" for="Login.pin" class="LblLev2Txt_sun4">
>>>> -<h:outputText value="#{compositeComponent.attributes.pinLabel}" />
>>>> +<h:outputText value="#{compositeComponent.attrs.pinLabel}" />
>>>> </label>
>>>> </span></div></td>
>>>> <td><div class="logInpLst"> Index:
>>>> jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> ===================================================================
>>>> ---
>>>> jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> (revision 5480)
>>>> +++
>>>> jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> (working copy)
>>>> -85,8 +85,8 @@
>>>>
>>>> <ui:define name="loginEvent">
>>>>
>>>> - <h:commandButton id="loginEvent"
>>>> value="#{compositeComponent.attributes.loginLabel}"
>>>> -
>>>> action="#{compositeComponent.attributes.model.loginAction}" +
>>>> <h:commandButton id="loginEvent"
>>>> value="#{compositeComponent.attrs.loginLabel}" +
>>>> action="#{compositeComponent.attrs.model.loginAction}"
>>>> onkeypress="javascript: submitenter(event,
>>>> 'loginButton', Login');" onclick="javascript:
>>>> submitAndDisable(this, 'Login');"
>>>> onfocus="javascript: if (this.disabled==0)
>>>> this.className='Btn1Hov'" Index:
>>>> jsf-demo/ezcomp03/src/main/webapp/resources/ezcomp/loginPanelTemplate.xhtml
>>>>
>>>> ===================================================================
>>>> ---
>>>> jsf-demo/ezcomp03/src/main/webapp/resources/ezcomp/loginPanelTemplate.xhtml
>>>> (revision 5480)
>>>> +++
>>>> jsf-demo/ezcomp03/src/main/webapp/resources/ezcomp/loginPanelTemplate.xhtml
>>>> (working copy)
>>>> -84,7 +84,7 @@
>>>> <tr><td nowrap="nowrap"><div class="logLbl">
>>>> &nbsp;<span class="LblLev2Txt">
>>>> <label id="sun_label17" for="Login.username" class="LblLev2Txt_sun4">
>>>> -<h:outputText
>>>> value="#{compositeComponent.attributes.usernameLabel}" />
>>>> +<h:outputText value="#{compositeComponent.attrs.usernameLabel}" />
>>>> </label>
>>>> </span></div></td>
>>>>
>>>> -97,7 +97,7 @@
>>>> <tr><td nowrap="nowrap"><div class="logLblLst">
>>>> &nbsp;<span class="LblLev2Txt">
>>>> <label id="sun_label19" for="Login.pin" class="LblLev2Txt_sun4">
>>>> -<h:outputText value="#{compositeComponent.attributes.pinLabel}" />
>>>> +<h:outputText value="#{compositeComponent.attrs.pinLabel}" />
>>>> </label>
>>>> </span></div></td>
>>>> <td><div class="logInpLst"> Index:
>>>> jsf-demo/ezcomp03/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> ===================================================================
>>>> ---
>>>> jsf-demo/ezcomp03/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> (revision 5480)
>>>> +++
>>>> jsf-demo/ezcomp03/src/main/webapp/resources/ezcomp/loginPanel.xhtml
>>>> (working copy)
>>>> -85,8 +85,8 @@
>>>>
>>>> <ui:define name="loginEvent">
>>>>
>>>> - <h:commandButton id="loginEvent"
>>>> value="#{compositeComponent.attributes.loginLabel}"
>>>> -
>>>> action="#{compositeComponent.attributes.model.loginAction}" +
>>>> <h:commandButton id="loginEvent"
>>>> value="#{compositeComponent.attrs.loginLabel}" +
>>>> action="#{compositeComponent.attrs.model.loginAction}"
>>>> onkeypress="javascript: submitenter(event,
>>>> 'loginButton', Login');" onclick="javascript:
>>>> submitAndDisable(this, 'Login');"
>>>> onfocus="javascript: if (this.disabled==0) this.className='Btn1Hov'"
>>>>
>>>>
>>>> ------------------------------------------------------------------------
>>>>
>>>>
>>>>
>>>> No virus found in this incoming message.
>>>> Checked by AVG - http://www.avg.com Version: 8.0.169 / Virus
>>>> Database: 270.7.3/1693 - Release Date: 9/26/2008 7:35 AM
>>>>
>>>>
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe_at_javaserverfaces.dev.java.net
>>> For additional commands, e-mail: dev-help_at_javaserverfaces.dev.java.net
>>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_javaserverfaces.dev.java.net
>> For additional commands, e-mail: dev-help_at_javaserverfaces.dev.java.net
>> ------------------------------------------------------------------------
>>
>>
>> No virus found in this incoming message.
>> Checked by AVG - http://www.avg.com Version: 8.0.169 / Virus
>> Database: 270.7.3/1693 - Release Date: 9/26/2008 7:35 AM
>>
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_javaserverfaces.dev.java.net
> For additional commands, e-mail: dev-help_at_javaserverfaces.dev.java.net
>





SECTION: Modified Files
----------------------------
M jsf-api/src/javax/faces/component/UIComponent.java
 - remove getAttrs() method in favor of new ELResolver described below.
 - remove unecessary transient modifier from instance variables

M jsf-ri/src/com/sun/faces/el/ELUtils.java
 - add the CompositeComponentAttributesELResolver after the ImplicitObjectELResolver

A jsf-ri/src/com/sun/faces/el/CompositeComponentAttributesELResolver.java
 - Given an expression such as #{compositeComponent.attrs.foo}:
   * the ImplicitObjectELResolver resolves compositeComponent
   * CompositeComponentAttributesELResolver will if base is a composite component
     and property is 'attrs' return a Map that will evaluate any
     ValueExpressions stored directly within the composite component's
     attribute map.
   * MapELResolver is passed an instance of the ExpressionEvalMap and calls
     get("foo") which will result in the value expression associated with
     foo to be evaluated.


SECTION: Diffs
----------------------------
Index: jsf-api/src/javax/faces/component/UIComponent.java
===================================================================
--- jsf-api/src/javax/faces/component/UIComponent.java (revision 5482)
+++ jsf-api/src/javax/faces/component/UIComponent.java (working copy)
@@ -44,8 +44,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -55,7 +53,6 @@
 import java.util.Locale;
 import java.util.Map;
 
-import java.util.Map.Entry;
 import java.util.MissingResourceException;
 import java.util.PropertyResourceBundle;
 import java.util.ResourceBundle;
@@ -239,85 +236,6 @@
     public abstract Map<String, Object> getAttributes();
     
     
- private transient Map<String, Object> valueExpressionEvaluatingAttrsMap;
-
- /**
- * <p class="changed_added_2_0">Like {_at_link #getAttributes}, except
- * that the <code>get()</code> implementation must call
- * <code>getValue()</code> on any result whose type is
- * <code>ValueExpression</code> and return the evaluated result.
- * </p>
- *
- * @since 2.0
- */
- public Map<String, Object> getAttrs() {
-
- if (null == valueExpressionEvaluatingAttrsMap) {
- valueExpressionEvaluatingAttrsMap = new Map<String, Object>() {
-
- private Map<String, Object> attrs = UIComponent.this.getAttributes();
-
- public void clear() {
- attrs.clear();
- }
-
- public boolean containsKey(Object key) {
- return attrs.containsKey(key);
- }
-
- public boolean containsValue(Object value) {
- return attrs.containsValue(value);
- }
-
- public Set<Entry<String, Object>> entrySet() {
- return attrs.entrySet();
- }
-
- public Object get(Object key) {
- Object result = attrs.get(key);
- // check if the result is an expression
- if (result instanceof ValueExpression) {
- ValueExpression ve = (ValueExpression) result;
- result = ve.getValue(FacesContext.getCurrentInstance().getELContext());
- }
- return result;
- }
-
- public boolean isEmpty() {
- return attrs.isEmpty();
- }
-
- public Set<String> keySet() {
- return attrs.keySet();
- }
-
- public Object put(String key, Object value) {
- return attrs.put(key, value);
- }
-
- public void putAll(Map<? extends String, ? extends Object> t) {
- attrs.putAll(t);
- }
-
- public Object remove(Object key) {
- return attrs.remove(key);
- }
-
- public int size() {
- return attrs.size();
- }
-
- public Collection<Object> values() {
- return attrs.values();
- }
-
- };
- }
-
- return valueExpressionEvaluatingAttrsMap;
- }
-
-
     // ---------------------------------------------------------------- Bindings
 
 
@@ -1424,8 +1342,8 @@
     }
 
 
- private transient UIComponent previouslyPushed = null;
- private transient UIComponent previouslyPushedCompositeComponent = null;
+ private UIComponent previouslyPushed = null;
+ private UIComponent previouslyPushedCompositeComponent = null;
 
     /**
      * <p class="changed_added_2_0">Push the current

Index: jsf-ri/src/com/sun/faces/el/CompositeComponentAttributesELResolver.java
===================================================================
--- jsf-ri/src/com/sun/faces/el/CompositeComponentAttributesELResolver.java (revision 0)
+++ jsf-ri/src/com/sun/faces/el/CompositeComponentAttributesELResolver.java (revision 0)
@@ -0,0 +1,313 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can obtain
+ * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
+ * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [year]
+ * [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.faces.el;
+
+import java.beans.FeatureDescriptor;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Collections;
+
+import javax.el.ELResolver;
+import javax.el.ELContext;
+import javax.el.ValueExpression;
+import javax.faces.component.UIComponent;
+import javax.faces.application.Resource;
+import javax.faces.context.FacesContext;
+
+import com.sun.faces.util.Util;
+
+/**
+ * <p>
+ * This {_at_link ELResolver} will handle the resolution of <code>attrs</code>
+ * when processing a composite component instance.
+ * </p>
+ */
+public class CompositeComponentAttributesELResolver extends ELResolver {
+
+ /**
+ * Implicit object related only to the compositeComponent implicitObject.
+ */
+ private static final String COMPOSITE_COMPONENT_ATTRIBUTES_NAME = "attrs";
+
+ /**
+ * Key to which we store the mappings between composite component instances
+ * and their ExpressionEvalMap.
+ */
+ private static final String EVAL_MAP_KEY =
+ CompositeComponentAttributesELResolver.class.getName() + "_EVAL_MAP";
+
+
+ // ------------------------------------------------- Methods from ELResolver
+
+
+ /**
+ * <p>
+ * If <code>base</code> is a composite component and <code>property</code>
+ * is <code>attrs</code>, return a new <code>ExpressionEvalMap</code>
+ * which wraps the composite component's attributes map.
+ * </p>
+ *
+ * <p>
+ * The <code>ExpressionEvalMap</code> simple evaluates any {_at_link ValueExpression}
+ * instances stored in the composite component's attribute map and returns
+ * the result.
+ * </p>
+ *
+ * @see javax.el.ELResolver#getValue(javax.el.ELContext, Object, Object)
+ * @see com.sun.faces.el.CompositeComponentAttributesELResolver.ExpressionEvalMap
+ */
+ public Object getValue(ELContext context, Object base, Object property) {
+
+ Util.notNull("context", context);
+
+ if (base != null
+ && (base instanceof UIComponent)
+ && property != null
+ && COMPOSITE_COMPONENT_ATTRIBUTES_NAME.equals(property.toString())) {
+ UIComponent c = (UIComponent) base;
+ if (c.getAttributes().get(Resource.COMPONENT_RESOURCE_KEY) != null) {
+ context.setPropertyResolved(true);
+ FacesContext ctx = (FacesContext) context.getContext(FacesContext.class);
+ return getEvalMapFor(c, ctx);
+ }
+ }
+
+ return null;
+
+ }
+
+
+ /**
+ * <p>
+ * Readonly, so return <code>null</code>.
+ * </p>
+ *
+ * @see ELResolver#getType(javax.el.ELContext, Object, Object)
+ */
+ public Class<?> getType(ELContext context, Object base, Object property) {
+
+ Util.notNull("context", context);
+ return null;
+
+ }
+
+
+ /**
+ * <p>
+ * This is a no-op.
+ * </p>
+ *
+ * @see ELResolver#setValue(javax.el.ELContext, Object, Object, Object)
+ */
+ public void setValue(ELContext context,
+ Object base,
+ Object property,
+ Object value) {
+
+ Util.notNull("context", context);
+
+ }
+
+
+ /**
+ * <p>
+ * Readonly, so return <code>true</code>
+ * </p>
+ *
+ * @see javax.el.ELResolver#isReadOnly(javax.el.ELContext, Object, Object)
+ */
+ public boolean isReadOnly(ELContext context, Object base, Object property) {
+
+ Util.notNull("context", context);
+ return true;
+
+ }
+
+
+ /**
+ * <p>
+ * This <code>ELResolver</code> currently returns no feature descriptors
+ * as we have no way to effectively iterate over the UIComponent
+ * attributes Map.
+ * </p>
+ *
+ * @see javax.el.ELResolver#getFeatureDescriptors(javax.el.ELContext, Object)
+ */
+ public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context,
+ Object base) {
+
+ Util.notNull("context", context);
+ Collection<FeatureDescriptor> descriptor = Collections.emptyList();
+ return descriptor.iterator();
+
+ }
+
+
+ /**
+ * <p>
+ * <code>attrs<code> is considered a <code>String</code> property.
+ * </p>
+ *
+ * @see javax.el.ELResolver#getCommonPropertyType(javax.el.ELContext, Object)
+ */
+ public Class<?> getCommonPropertyType(ELContext context, Object base) {
+
+ Util.notNull("context", context);
+ return String.class;
+
+ }
+
+
+ // --------------------------------------------------------- Private Methods
+
+
+ /**
+ * <p>
+ * Creates (if necessary) and caches an <code>ExpressionEvalMap</code>
+ * instance associated with the owning {_at_link UIComponent}
+ * </p>
+ *
+ * @param c the owning {_at_link UIComponent}
+ * @param ctx the {_at_link FacesContext} for the current request
+ * @return an <code>ExpressionEvalMap</code> for the specified component
+ */
+ public Map<String,Object> getEvalMapFor(UIComponent c, FacesContext ctx) {
+
+ Map<Object, Object> ctxAttributes = ctx.getAttributes();
+ //noinspection unchecked
+ Map<UIComponent,Map<String,Object>> topMap =
+ (Map<UIComponent,Map<String,Object>>) ctxAttributes.get(EVAL_MAP_KEY);
+ Map<String,Object> evalMap = null;
+ if (topMap == null) {
+ topMap = new HashMap<UIComponent,Map<String,Object>>();
+ ctxAttributes.put(EVAL_MAP_KEY, topMap);
+ evalMap = new ExpressionEvalMap(c.getAttributes());
+ topMap.put(c, evalMap);
+ }
+ if (evalMap == null) {
+ evalMap = topMap.get(c);
+ if (evalMap == null) {
+ evalMap = new ExpressionEvalMap(c.getAttributes());
+ topMap.put(c, evalMap);
+ }
+ }
+ return evalMap;
+
+ }
+
+
+ // ---------------------------------------------------------- Nested Classes
+
+
+ /**
+ * Simple Map implementation to evaluate any <code>ValueExpression</code>
+ * stored directly within the provided attributes map.
+ */
+ private static final class ExpressionEvalMap implements Map<String,Object> {
+
+ private Map<String,Object> attributesMap;
+
+
+ // -------------------------------------------------------- Constructors
+
+
+ ExpressionEvalMap(Map<String,Object> attributesMap) {
+
+ this.attributesMap = attributesMap;
+
+ }
+
+
+ // ---------------------------------------------------- Methods from Map
+
+
+ public int size() {
+ return attributesMap.size();
+ }
+
+ public boolean isEmpty() {
+ return attributesMap.isEmpty();
+ }
+
+ public boolean containsKey(Object key) {
+ return attributesMap.containsKey(key);
+ }
+
+ public boolean containsValue(Object value) {
+ return attributesMap.containsValue(value);
+ }
+
+ public Object get(Object key) {
+ Object v = attributesMap.get(key);
+ if (v != null && v instanceof ValueExpression) {
+ return (((ValueExpression) v).getValue(FacesContext.getCurrentInstance().getELContext()));
+ }
+ return v;
+ }
+
+ public Object put(String key, Object value) {
+ return attributesMap.put(key, value);
+ }
+
+ public Object remove(Object key) {
+ return attributesMap.remove(key);
+ }
+
+ public void putAll(Map<? extends String,?> t) {
+ attributesMap.putAll(t);
+ }
+
+ public void clear() {
+ attributesMap.clear();
+ }
+
+ public Set<String> keySet() {
+ return attributesMap.keySet();
+ }
+
+ public Collection<Object> values() {
+ return attributesMap.values();
+ }
+
+ public Set<Map.Entry<String,Object>> entrySet() {
+ return attributesMap.entrySet();
+ }
+ }
+}

Property changes on: jsf-ri/src/com/sun/faces/el/CompositeComponentAttributesELResolver.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: jsf-ri/src/com/sun/faces/el/ELUtils.java
===================================================================
--- jsf-ri/src/com/sun/faces/el/ELUtils.java (revision 5482)
+++ jsf-ri/src/com/sun/faces/el/ELUtils.java (working copy)
@@ -128,7 +128,11 @@
     public static final ResourceELResolver RESOURCE_RESOLVER =
           new ResourceELResolver();
 
+ public static final CompositeComponentAttributesELResolver COMPOSITE_COMPONENT_ATTRIBUTES_EL_RESOLVER =
+ new CompositeComponentAttributesELResolver();
 
+
+
     // ------------------------------------------------------------ Constructors
 
 
@@ -163,6 +167,7 @@
         }
 
         composite.add(IMPLICIT_RESOLVER);
+ composite.add(COMPOSITE_COMPONENT_ATTRIBUTES_EL_RESOLVER);
         addELResolvers(composite, associate.getELResolversFromFacesConfig());
         addVariableResolvers(composite, associate);
         addPropertyResolvers(composite, associate);


SECTION: New Files
----------------------------
SEE ATTACHMENTS