myfaces-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jak...@apache.org
Subject svn commit: r911789 - in /myfaces/core/trunk: api/src/main/java/javax/faces/component/ impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/ impl/src/main/java/org/apache/myfaces/view/facelets/ impl/src/main/java/org/apache/myfaces/...
Date Fri, 19 Feb 2010 11:59:22 GMT
Author: jakobk
Date: Fri Feb 19 11:59:22 2010
New Revision: 911789

URL: http://svn.apache.org/viewvc?rev=911789&view=rev
Log:
MYFACES-2561 StackOverflowError if a composite component implementation uses another composite
component

Added:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/CompositeComponentELUtils.java
  (with props)
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationMethodExpression.java
  (with props)
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationValueExpression.java
  (with props)
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/ValueExpressionMethodExpression.java
  (with props)
Removed:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/TagValueExpressionMethodExpression.java
Modified:
    myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/CompositeComponentImplicitObject.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/TagAttributeImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/InterfaceHandler.java

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.java?rev=911789&r1=911788&r2=911789&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.java Fri Feb 19
11:59:22 2010
@@ -128,7 +128,13 @@
      * where the definition of this component is.
      */
     public static final String VIEW_LOCATION_KEY = "javax.faces.component.VIEW_LOCATION_KEY";
+    
+    /**
+     * The key under which the component stack is stored in the FacesContext.
+     * ATTENTION: this constant is duplicate in CompositeComponentExpressionUtils.
+     */
     private static final String _COMPONENT_STACK = "componentStack:" + UIComponent.class.getName();
+    
     Map<Class<? extends SystemEvent>, List<SystemEventListener>> _systemEventListenerClassMap;
     
     /**

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/CompositeComponentImplicitObject.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/CompositeComponentImplicitObject.java?rev=911789&r1=911788&r2=911789&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/CompositeComponentImplicitObject.java
(original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/CompositeComponentImplicitObject.java
Fri Feb 19 11:59:22 2010
@@ -22,6 +22,9 @@
 
 import javax.el.ELContext;
 import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
 
 /**
  * Encapsulates information needed by the ImplicitObjectResolver
@@ -42,7 +45,18 @@
     @Override
     public Object getValue(ELContext context)
     {
-        return UIComponent.getCurrentCompositeComponent(facesContext(context));
+        FacesContext facesContext = facesContext(context);
+        
+        // Look for the attribute set by LocationValueExpression
+        // or LocationMethodExpression on the FacesContext
+        UIComponent cc = (UIComponent) facesContext.getAttributes()
+                .get(CompositeComponentELUtils.CURRENT_COMPOSITE_COMPONENT_KEY);
+        if (cc == null)
+        {
+            // take the composite component from the stack
+            cc = UIComponent.getCurrentCompositeComponent(facesContext(context));
+        }
+        return cc;
     }
 
     @Override

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java?rev=911789&r1=911788&r2=911789&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
(original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
Fri Feb 19 11:59:22 2010
@@ -57,12 +57,14 @@
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
 import javax.faces.event.ActionEvent;
+import javax.faces.event.ActionListener;
 import javax.faces.event.MethodExpressionActionListener;
 import javax.faces.event.MethodExpressionValueChangeListener;
 import javax.faces.event.PhaseId;
 import javax.faces.event.PostAddToViewEvent;
 import javax.faces.event.PreRemoveFromViewEvent;
 import javax.faces.event.ValueChangeEvent;
+import javax.faces.event.ValueChangeListener;
 import javax.faces.render.RenderKit;
 import javax.faces.validator.MethodExpressionValidator;
 import javax.faces.view.ActionSource2AttachedObjectHandler;
@@ -96,6 +98,8 @@
 import org.apache.myfaces.view.facelets.compiler.Compiler;
 import org.apache.myfaces.view.facelets.compiler.SAXCompiler;
 import org.apache.myfaces.view.facelets.compiler.TagLibraryConfig;
+import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
+import org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression;
 import org.apache.myfaces.view.facelets.el.VariableMapperWrapper;
 import org.apache.myfaces.view.facelets.impl.DefaultFaceletFactory;
 import org.apache.myfaces.view.facelets.impl.DefaultResourceResolver;
@@ -804,6 +808,15 @@
                 String attributeExpressionString = attributeNameValueExpression.getExpressionString();
                 MethodExpression methodExpression = null;
                 
+                // if the expression String contains a reference to the current composite
+                // component #{cc}, the MethodExpression has to be invoked indirectly (via
+                // a ValueExpression that points to the real MethodExpression). This happens
+                // when other composite components are nested in composite components' implementations.
+                if (CompositeComponentELUtils.isCompositeComponentExpression(attributeExpressionString))
+                {
+                    methodExpression = new ValueExpressionMethodExpression(attributeNameValueExpression);
+                }
+                
                 if (isKnownMethod)
                 {
                     for (String target : targetsArray)
@@ -816,33 +829,50 @@
                                 log.severe("Inner component " + target + " not found when
retargetMethodExpressions");
                             continue;
                         }
-
+                        
                         if ("action".equals(attributeName))
                         {
                             // target is ActionSource2
-                            methodExpression = context.getApplication().getExpressionFactory().
-                                    createMethodExpression(context.getELContext(),
-                                            attributeExpressionString, Object.class, new
Class[]{});
+                            if (methodExpression == null)
+                            {
+                                methodExpression = context.getApplication().getExpressionFactory().
+                                        createMethodExpression(context.getELContext(),
+                                                attributeExpressionString, Object.class,
new Class[]{});
+                            }
                             
                             ((ActionSource2)innerComponent).setActionExpression(methodExpression);
                         }
                         else if ("actionListener".equals(attributeName))
                         {
                            // target is ActionSource2
-                            methodExpression = context.getApplication().getExpressionFactory().
-                                    createMethodExpression(context.getELContext(),
-                                            attributeExpressionString, Void.TYPE, new Class[]{ActionEvent.class});
+                            ActionListener actionListener = null;
+                            if (methodExpression == null)
+                            {
+                                methodExpression = context.getApplication().getExpressionFactory().
+                                        createMethodExpression(context.getELContext(),
+                                                attributeExpressionString, Void.TYPE, new
Class[]{ActionEvent.class});
+                                actionListener = new MethodExpressionActionListener(methodExpression);
+                            }
+                            else
+                            {
+                                // FIXME this will maybe need changes, because the second
methodExpression
+                                // is supposed to have zero args, but the underlying MethodExpression

+                                // won't fulfill this requirement. -=Jakob Korherr=-
+                                actionListener = new MethodExpressionActionListener(methodExpression,
methodExpression);
+                            }
                             
-                            ((ActionSource)innerComponent).addActionListener(
-                                    new MethodExpressionActionListener(methodExpression));
+                            ((ActionSource)innerComponent).addActionListener(actionListener);
                         }
                         else if ("validator".equals(attributeName))
                         {
                             // target is EditableValueHolder
-                            methodExpression = context.getApplication().getExpressionFactory().
-                                    createMethodExpression(context.getELContext(),
-                                        attributeExpressionString, Void.TYPE, 
-                                        new Class[]{FacesContext.class, UIComponent.class,
Object.class});
+                            if (methodExpression == null)
+                            {
+                                methodExpression = context.getApplication().getExpressionFactory().
+                                        createMethodExpression(context.getELContext(),
+                                            attributeExpressionString, Void.TYPE, 
+                                            new Class[]{FacesContext.class, UIComponent.class,
Object.class});
+                            }
 
                             ((EditableValueHolder)innerComponent).addValidator(
                                     new MethodExpressionValidator(methodExpression));
@@ -850,13 +880,24 @@
                         else if ("valueChangeListener".equals(attributeName))
                         {
                             // target is EditableValueHolder
-                            methodExpression = context.getApplication().getExpressionFactory().
-                                    createMethodExpression(context.getELContext(),
-                                            attributeExpressionString, Void.TYPE, 
-                                            new Class[]{ValueChangeEvent.class});
+                            ValueChangeListener valueChangeListener = null;
+                            if (methodExpression == null)
+                            {
+                                methodExpression = context.getApplication().getExpressionFactory().
+                                        createMethodExpression(context.getELContext(),
+                                                attributeExpressionString, Void.TYPE, 
+                                                new Class[]{ValueChangeEvent.class});
+                                valueChangeListener = new MethodExpressionValueChangeListener(methodExpression);
+                            }
+                            else
+                            {
+                                // FIXME this will maybe need changes, because the second
methodExpression
+                                // is supposed to have zero args, but the underlying MethodExpression

+                                // won't fulfill this requirement. -=Jakob Korherr=-
+                                valueChangeListener = new MethodExpressionValueChangeListener(methodExpression,
methodExpression);
+                            }
 
-                            ((EditableValueHolder)innerComponent).addValueChangeListener(
-                                    new MethodExpressionValueChangeListener(methodExpression));
+                            ((EditableValueHolder)innerComponent).addValueChangeListener(valueChangeListener);
                         }
                     }
                 }
@@ -865,11 +906,14 @@
                     // composite:attribute targets property only has sense for action, actionListener,
                     // validator or valueChangeListener. This means we have to retarget the
method expression
                     // to the topLevelComponent.
-                    methodSignature = methodSignature.trim();
-                    methodExpression = context.getApplication().getExpressionFactory().
-                    createMethodExpression(context.getELContext(),
-                            attributeExpressionString, _getReturnType(methodSignature), 
-                            _getParameters(methodSignature));
+                    if (methodExpression == null)
+                    {
+                        methodSignature = methodSignature.trim();
+                        methodExpression = context.getApplication().getExpressionFactory().
+                        createMethodExpression(context.getELContext(),
+                                attributeExpressionString, _getReturnType(methodSignature),

+                                _getParameters(methodSignature));
+                    }
                     topLevelComponent.getAttributes().put(attributeName, methodExpression);
                 }
                 

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/CompositeComponentELUtils.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/CompositeComponentELUtils.java?rev=911789&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/CompositeComponentELUtils.java
(added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/CompositeComponentELUtils.java
Fri Feb 19 11:59:22 2010
@@ -0,0 +1,160 @@
+/*
+ * 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.view.facelets.el;
+
+import java.util.LinkedList;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.view.Location;
+
+/**
+ * Utility class for composite components when used in EL Expressions --> #{cc}
+ * 
+ * @author Jakob Korherr (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public final class CompositeComponentELUtils
+{
+    
+    /**
+     * The key under which the component stack is stored in the FacesContext.
+     * ATTENTION: this constant is duplicate in UIComponent.
+     */
+    public static final String COMPONENT_STACK = "componentStack:" + UIComponent.class.getName();
+    
+    /**
+     * The key under which the current composite component is stored in the attribute
+     * map of the FacesContext.
+     */
+    public static final String CURRENT_COMPOSITE_COMPONENT_KEY = "org.apache.myfaces.compositecomponent.current";
+    
+    /**
+     * The key under which the Location of the composite componente is stored
+     * in the attributes map of the component by InterfaceHandler.
+     */
+    public static final String LOCATION_KEY = "org.apache.myfaces.compositecomponent.location";
+    
+    /**
+     * A regular expression used to determine if cc is used in an expression String.
+     */
+    public static final String CC_EXPRESSION_REGEX = ".*[^\\w\\.]cc[^\\w].*";
+    
+    /**
+     * private constructor
+     */
+    private CompositeComponentELUtils()
+    {
+        // no instantiation of this class
+    }
+    
+    /**
+     * Trys to find a composite component on the composite component stack
+     * and using UIComponent.getCurrentCompositeComponent() based on the 
+     * location of the facelet page that generated the composite component.
+     * @param facesContext
+     * @param location
+     * @return
+     */
+    public static UIComponent getCompositeComponentBasedOnLocation(FacesContext facesContext,

+            Location location)
+    {
+        // look on the component stack
+        LinkedList<UIComponent> componentStack = getComponentStack(facesContext);
+        if (componentStack == null || componentStack.isEmpty())
+        {
+            // no components on the stack
+            return null;
+        }
+        
+        // try to find the right composite component
+        for (UIComponent component : componentStack)
+        {
+            if (UIComponent.isCompositeComponent(component))
+            {
+                Location componentLocation = (Location) component.getAttributes().get(LOCATION_KEY);
+                if (componentLocation != null 
+                        && componentLocation.getPath().equals(location.getPath()))
+                {
+                    return component;
+                }
+            }
+        }
+        
+        // try to find it using UIComponent.getCurrentCompositeComponent()
+        UIComponent component = UIComponent.getCurrentCompositeComponent(facesContext);
+        while (component != null)
+        {
+            Location componentLocation = (Location) component.getAttributes().get(LOCATION_KEY);
+            if (componentLocation != null 
+                    && componentLocation.getPath().equals(location.getPath()))
+            {
+                return component;
+            }
+            // get the composite component's parent
+            component = UIComponent.getCompositeComponentParent(component);
+        }
+        
+        // not found
+        return null;
+    }
+    
+    /**
+     * Gets the current component stack from the FacesContext.
+     * @param facesContext
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static LinkedList<UIComponent> getComponentStack(FacesContext facesContext)
+    {
+        return (LinkedList<UIComponent>) facesContext.getAttributes().get(COMPONENT_STACK);
+    }
+    
+    /**
+     * Trys to get the composite component using getCompositeComponentBasedOnLocation()
+     * and saves it in an attribute on the FacesContext, which is then used by 
+     * CompositeComponentImplicitObject.
+     * @param facesContext
+     * @param location
+     */
+    public static void saveCompositeComponentForResolver(FacesContext facesContext, Location
location)
+    {
+        UIComponent cc = getCompositeComponentBasedOnLocation(facesContext, location);
+        facesContext.getAttributes().put(CURRENT_COMPOSITE_COMPONENT_KEY, cc);
+    }
+    
+    /**
+     * Removes the composite component from the attribute map of the FacesContext.
+     * @param facesContext
+     */
+    public static void removeCompositeComponentForResolver(FacesContext facesContext)
+    {
+        facesContext.getAttributes().remove(CURRENT_COMPOSITE_COMPONENT_KEY);
+    }
+    
+    /**
+     * Tests if the expression refers to the current composite component: #{cc}
+     * @return
+     */
+    public static boolean isCompositeComponentExpression(String expression)
+    {
+        return expression.matches(CC_EXPRESSION_REGEX);
+    }
+    
+}

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/CompositeComponentELUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/CompositeComponentELUtils.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/CompositeComponentELUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationMethodExpression.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationMethodExpression.java?rev=911789&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationMethodExpression.java
(added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationMethodExpression.java
Fri Feb 19 11:59:22 2010
@@ -0,0 +1,115 @@
+/*
+ * 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.view.facelets.el;
+
+import javax.el.ELContext;
+import javax.el.MethodExpression;
+import javax.el.MethodInfo;
+import javax.faces.context.FacesContext;
+import javax.faces.view.Location;
+
+/**
+ * A MethodExpression that contains the original MethodExpression and
+ * the Location of the facelet file from which the MethodExpression was
+ * created. This is needed when the current composite component (cc) 
+ * has to be resolved by the MethodExpression, because #{cc} refers to the
+ * composite component which is implemented in the file the MethodExpression
+ * comes from and not the one currently on top of the composite component stack.
+ * 
+ * This MethodExpression implementation passes through all methods to the delegate
+ * MethodExpression, but saves the related composite component in a FacesContext attribute

+ * before the invocation of the method on the delegate and removes it afterwards.
+ * 
+ * @author Jakob Korherr (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public class LocationMethodExpression extends MethodExpression
+{
+
+    private static final long serialVersionUID = 1634644578979226893L;
+    
+    private Location location;
+    private MethodExpression delegate;
+    
+    public LocationMethodExpression(Location location, MethodExpression delegate)
+    {
+        this.location = location;
+        this.delegate = delegate;
+    }
+    
+    public Location getLocation()
+    {
+        return location;
+    }
+    
+    @Override
+    public MethodInfo getMethodInfo(ELContext context)
+    {
+        FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
+        CompositeComponentELUtils.saveCompositeComponentForResolver(facesContext, location);
+        try
+        {
+            return delegate.getMethodInfo(context);
+        }
+        finally
+        {
+            CompositeComponentELUtils.removeCompositeComponentForResolver(facesContext);
+        }
+    }
+
+    @Override
+    public Object invoke(ELContext context, Object[] params)
+    {
+        FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
+        CompositeComponentELUtils.saveCompositeComponentForResolver(facesContext, location);
+        try
+        {
+            return delegate.invoke(context, params);
+        }
+        finally
+        {
+            CompositeComponentELUtils.removeCompositeComponentForResolver(facesContext);
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public String getExpressionString()
+    {
+        return delegate.getExpressionString();
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return delegate.hashCode();
+    }
+
+    @Override
+    public boolean isLiteralText()
+    {
+        return delegate.isLiteralText();
+    }
+
+}

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationMethodExpression.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationMethodExpression.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationMethodExpression.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationValueExpression.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationValueExpression.java?rev=911789&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationValueExpression.java
(added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationValueExpression.java
Fri Feb 19 11:59:22 2010
@@ -0,0 +1,150 @@
+/*
+ * 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.view.facelets.el;
+
+import javax.el.ELContext;
+import javax.el.ValueExpression;
+import javax.faces.context.FacesContext;
+import javax.faces.view.Location;
+
+/**
+ * A ValueExpression that contains the original ValueExpression and
+ * the Location of the facelet file from which the ValueExpression was
+ * created. This is needed when the current composite component (cc) 
+ * has to be resolved by the ValueExpression, because #{cc} refers to the
+ * composite component which is implemented in the file the ValueExpression
+ * comes from and not the one currently on top of the composite component stack.
+ * 
+ * This ValueExpression implementation passes through all methods to the delegate
+ * ValueExpression, but saves the related composite component in a FacesContext attribute

+ * before the invocation of the method on the delegate and removes it afterwards. 
+ * 
+ * @author Jakob Korherr (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public class LocationValueExpression extends ValueExpression
+{
+    
+    private static final long serialVersionUID = -5636849184764526288L;
+    
+    private Location location;
+    private ValueExpression delegate;
+    
+    public LocationValueExpression(Location location, ValueExpression delegate)
+    {
+        this.location = location;
+        this.delegate = delegate;
+    }
+    
+    public Location getLocation()
+    {
+        return location;
+    }
+    
+    @Override
+    public Class<?> getExpectedType()
+    {
+        return delegate.getExpectedType();
+    }
+
+    @Override
+    public Class<?> getType(ELContext context)
+    {
+        FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
+        CompositeComponentELUtils.saveCompositeComponentForResolver(facesContext, location);
+        try
+        {
+            return delegate.getType(context);
+        }
+        finally
+        {
+            CompositeComponentELUtils.removeCompositeComponentForResolver(facesContext);
+        }
+    }
+
+    @Override
+    public Object getValue(ELContext context)
+    {
+        FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
+        CompositeComponentELUtils.saveCompositeComponentForResolver(facesContext, location);
+        try
+        {
+            return delegate.getValue(context);
+        }
+        finally
+        {
+            CompositeComponentELUtils.removeCompositeComponentForResolver(facesContext);
+        }
+    }
+
+    @Override
+    public boolean isReadOnly(ELContext context)
+    {
+        FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
+        CompositeComponentELUtils.saveCompositeComponentForResolver(facesContext, location);
+        try
+        {
+            return delegate.isReadOnly(context);
+        }
+        finally
+        {
+            CompositeComponentELUtils.removeCompositeComponentForResolver(facesContext);
+        }
+    }
+
+    @Override
+    public void setValue(ELContext context, Object value)
+    {
+        FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
+        CompositeComponentELUtils.saveCompositeComponentForResolver(facesContext, location);
+        try
+        {
+            delegate.setValue(context, value);
+        }
+        finally
+        {
+            CompositeComponentELUtils.removeCompositeComponentForResolver(facesContext);
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public String getExpressionString()
+    {
+        return delegate.getExpressionString();
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return delegate.hashCode();
+    }
+
+    @Override
+    public boolean isLiteralText()
+    {
+        return delegate.isLiteralText();
+    }
+    
+}

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationValueExpression.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationValueExpression.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/LocationValueExpression.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/ValueExpressionMethodExpression.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/ValueExpressionMethodExpression.java?rev=911789&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/ValueExpressionMethodExpression.java
(added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/ValueExpressionMethodExpression.java
Fri Feb 19 11:59:22 2010
@@ -0,0 +1,94 @@
+/*
+ * 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.view.facelets.el;
+
+import javax.el.ELContext;
+import javax.el.MethodExpression;
+import javax.el.MethodInfo;
+import javax.el.ValueExpression;
+import javax.faces.context.FacesContext;
+
+/**
+ * This MethodExpression contains a ValueExpression which resolves to 
+ * the "real" MethodExpression that should be invoked. This is needed 
+ * when the MethodExpression is on the parent composite component attribute map.
+ * See FaceletViewDeclarationLanguage.retargetMethodExpressions() for details.
+ * 
+ * @author Jakob Korherr (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public class ValueExpressionMethodExpression extends MethodExpression
+{
+    
+    private static final long serialVersionUID = -2847633717581167765L;
+    
+    private ValueExpression valueExpression;
+    
+    public ValueExpressionMethodExpression(ValueExpression valueExpression)
+    {
+        this.valueExpression = valueExpression;   
+    }
+
+    @Override
+    public MethodInfo getMethodInfo(ELContext context)
+    {
+        return getMethodExpression(context).getMethodInfo(context);
+    }
+
+    @Override
+    public Object invoke(ELContext context, Object[] params)
+    {
+        return getMethodExpression(context).invoke(context, params);
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return getMethodExpression().equals(obj);
+    }
+
+    @Override
+    public String getExpressionString()
+    {
+        return getMethodExpression().getExpressionString();
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return getMethodExpression().hashCode();
+    }
+
+    @Override
+    public boolean isLiteralText()
+    {
+        return getMethodExpression().isLiteralText();
+    }
+    
+    private MethodExpression getMethodExpression()
+    {
+        return getMethodExpression(FacesContext.getCurrentInstance().getELContext());
+    }
+    
+    private MethodExpression getMethodExpression(ELContext context)
+    {
+        return (MethodExpression) valueExpression.getValue(context);
+    }
+
+}

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/ValueExpressionMethodExpression.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/ValueExpressionMethodExpression.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/ValueExpressionMethodExpression.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/TagAttributeImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/TagAttributeImpl.java?rev=911789&r1=911788&r2=911789&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/TagAttributeImpl.java
(original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/TagAttributeImpl.java
Fri Feb 19 11:59:22 2010
@@ -22,14 +22,18 @@
 import javax.el.ExpressionFactory;
 import javax.el.MethodExpression;
 import javax.el.ValueExpression;
-import javax.faces.view.facelets.FaceletContext;
 import javax.faces.view.Location;
+import javax.faces.view.facelets.FaceletContext;
 import javax.faces.view.facelets.TagAttribute;
 import javax.faces.view.facelets.TagAttributeException;
 
+import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
 import org.apache.myfaces.view.facelets.el.ELText;
+import org.apache.myfaces.view.facelets.el.LocationMethodExpression;
+import org.apache.myfaces.view.facelets.el.LocationValueExpression;
 import org.apache.myfaces.view.facelets.el.TagMethodExpression;
 import org.apache.myfaces.view.facelets.el.TagValueExpression;
+import org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression;
 
 /**
  * Representation of a Tag's attribute in a Facelet File
@@ -153,6 +157,8 @@
     {
         try
         {
+            MethodExpression methodExpression = null;
+            
             // From this point we can suppose this attribute contains a ELExpression
             // Now we have to check if the expression points to a composite component attribute
map
             // and if so deal with it as an indirection.
@@ -162,13 +168,25 @@
                 // create a pointer that are referred to the real one that is created in
other side
                 // (see VDL.retargetMethodExpressions for details)
                 ValueExpression valueExpr = this.getValueExpression(ctx, MethodExpression.class);
-                return new TagValueExpressionMethodExpression(this, valueExpr);
+                methodExpression = new ValueExpressionMethodExpression(valueExpr);
             }
             else
             {
                 ExpressionFactory f = ctx.getExpressionFactory();
-                return new TagMethodExpression(this, f.createMethodExpression(ctx, this.value,
type, paramTypes));
+                methodExpression = f.createMethodExpression(ctx, this.value, type, paramTypes);
+                    
+                // if the MethodExpression contains a reference to the current composite
+                // component, the Location also has to be stored in the MethodExpression

+                // to be able to resolve the right composite component (the one that was
+                // created from the file the Location is pointing to) later.
+                // (see MYFACES-2561 for details)
+                if (CompositeComponentELUtils.isCompositeComponentExpression(this.value))
+                {
+                    methodExpression = new LocationMethodExpression(getLocation(), methodExpression);
+                }
             }
+            
+            return new TagMethodExpression(this, methodExpression);
         }
         catch (Exception e)
         {
@@ -196,7 +214,7 @@
         }
         return false;
     }
-
+    
     /**
      * The resolved Namespace for this attribute
      * 
@@ -323,7 +341,19 @@
         try
         {
             ExpressionFactory f = ctx.getExpressionFactory();
-            return new TagValueExpression(this, f.createValueExpression(ctx, this.value,
type));
+            ValueExpression valueExpression = f.createValueExpression(ctx, this.value, type);
+            
+            // if the ValueExpression contains a reference to the current composite
+            // component, the Location also has to be stored in the ValueExpression 
+            // to be able to resolve the right composite component (the one that was
+            // created from the file the Location is pointing to) later.
+            // (see MYFACES-2561 for details)
+            if (CompositeComponentELUtils.isCompositeComponentExpression(this.value))
+            {
+                valueExpression = new LocationValueExpression(getLocation(), valueExpression);
+            }
+            
+            return new TagValueExpression(this, valueExpression);
         }
         catch (Exception e)
         {

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/InterfaceHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/InterfaceHandler.java?rev=911789&r1=911788&r2=911789&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/InterfaceHandler.java
(original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/InterfaceHandler.java
Fri Feb 19 11:59:22 2010
@@ -34,6 +34,7 @@
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
 import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
+import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
 import org.apache.myfaces.view.facelets.tag.TagHandlerUtils;
 
 /**
@@ -156,6 +157,11 @@
     public void apply(FaceletContext ctx, UIComponent parent)
             throws IOException
     {
+        // Store the current Location on the parent (the location is needed
+        // to resolve the related composite component via #{cc} properly).
+        _getCompositeBaseParent(parent).getAttributes()
+                .put(CompositeComponentELUtils.LOCATION_KEY, this.tag.getLocation());
+        
         // Only apply if we are building composite component metadata,
         // in other words we are calling ViewDeclarationLanguage.getComponentMetadata
         if ( ((AbstractFaceletContext)ctx).isBuildingCompositeComponentMetadata())



Mime
View raw message