You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2013/04/22 21:04:46 UTC

svn commit: r1470662 - in /myfaces/core/branches/2.1.x/impl/src: main/java/org/apache/myfaces/view/facelets/ main/java/org/apache/myfaces/view/facelets/el/ main/java/org/apache/myfaces/view/facelets/impl/ main/java/org/apache/myfaces/view/facelets/tag/...

Author: lu4242
Date: Mon Apr 22 19:04:45 2013
New Revision: 1470662

URL: http://svn.apache.org/r1470662
Log:
MYFACES-3711 Add alwaysRecompile mode for EL Expression Cache Mode 

Added:
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletCache.java   (with props)
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/CacheELFaceletCacheImpl.java
      - copied, changed from r1468642, myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCacheImpl.java
    myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/el/CacheELExpressionsAlwaysRecompileTestCase.java   (with props)
    myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/includetagtest1.xhtml
      - copied, changed from r1468642, myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1.xhtml
    myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/user.taglib.xml
      - copied, changed from r1468642, myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/user.taglib.xml
    myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1.xhtml
      - copied, changed from r1468642, myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1.xhtml
    myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1_1.xhtml
      - copied, changed from r1468642, myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1_1.xhtml
    myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1_2.xhtml
      - copied, changed from r1468642, myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1_1.xhtml
Modified:
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/ELExpressionCacheMode.java
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletFactory.java
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/TemplateContext.java
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/el/DefaultVariableMapper.java
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFacelet.java
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletFactory.java
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCacheFactoryImpl.java
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/TemplateContextImpl.java
    myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/UserTagHandler.java
    myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/tag/ui/IncludeParamTestCase.java

Added: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletCache.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletCache.java?rev=1470662&view=auto
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletCache.java (added)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletCache.java Mon Apr 22 19:04:45 2013
@@ -0,0 +1,98 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.net.URL;
+import javax.faces.view.facelets.FaceletCache;
+import javax.faces.view.facelets.FaceletContext;
+
+/**
+ * Extended FaceletCache contract that supports additional Myfaces specific concepts
+ * that are necessary to implement.
+ *
+ * @author Leonardo Uribe
+ * @since 2.1.12
+ */
+public abstract class AbstractFaceletCache<V> extends FaceletCache<V>
+{
+    private FaceletCache.MemberFactory<V> _compositeComponentMetadataFaceletFactory;
+
+    /**
+     * Retrieve a Facelet instance from the cache given the passed url, but taking into
+     * account the facelet context too, so the cache can implement special rules 
+     * according to the context for recompile the facelet if necessary.
+     * 
+     * @param ctx
+     * @param url
+     * @return
+     * @throws IOException 
+     */
+    public V getFacelet(FaceletContext ctx, URL url) throws IOException
+    {
+        return getFacelet(url);
+    }
+    
+    /**
+     * Retrieve or create a Facelet instance used to create composite component 
+     * metadata from the cache.
+     * 
+     * @param url
+     * @return
+     * @throws IOException 
+     */
+    public abstract V getCompositeComponentMetadataFacelet(URL url) throws IOException;
+
+    /**
+     * Check if the composite component metadata facelet associated with the url is
+     * cached or not.
+     * 
+     * @param url
+     * @return 
+     */
+    public abstract boolean isCompositeComponentMetadataFaceletCached(URL url);
+    
+    /**
+     * Set the factories used for create Facelet instances.
+     * 
+     * @param faceletFactory
+     * @param viewMetadataFaceletFactory
+     * @param compositeComponentMetadataFaceletFactory 
+     */
+    protected void setMemberFactories(FaceletCache.MemberFactory<V> faceletFactory,
+                                      FaceletCache.MemberFactory<V> viewMetadataFaceletFactory,
+                                      FaceletCache.MemberFactory<V> compositeComponentMetadataFaceletFactory)
+    {
+        if  (compositeComponentMetadataFaceletFactory == null)
+        {
+            throw new NullPointerException("viewMetadataFaceletFactory is null");
+        }
+        _compositeComponentMetadataFaceletFactory = compositeComponentMetadataFaceletFactory;
+        setMemberFactories(faceletFactory, viewMetadataFaceletFactory);
+    }
+    
+    /**
+     * 
+     * @return 
+     */
+    protected FaceletCache.MemberFactory<V> getCompositeComponentMetadataMemberFactory()
+    {
+        return _compositeComponentMetadataFaceletFactory;
+    }    
+}

Propchange: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/ELExpressionCacheMode.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/ELExpressionCacheMode.java?rev=1470662&r1=1470661&r2=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/ELExpressionCacheMode.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/ELExpressionCacheMode.java Mon Apr 22 19:04:45 2013
@@ -52,5 +52,16 @@ public enum ELExpressionCacheMode
      * Note if ui:param is used, each template call should define the same
      * param count, even if only just a few are used. 
      */
-    always
+    always,
+    
+    /**
+     * Does not cache expressions on these cases:
+     * - An expression uses a variable resolved through VariableMapper
+     * 
+     * It uses an alternate FaceletCache that implements AbstractFaceletCache
+     * contract and force recompile the facelet in case additional ui:param
+     * instances are detected.
+     * 
+     */
+    alwaysRecompile,
 }

Modified: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletFactory.java?rev=1470662&r1=1470661&r2=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletFactory.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletFactory.java Mon Apr 22 19:04:45 2013
@@ -23,6 +23,7 @@ import javax.faces.FacesException;
 import javax.faces.view.facelets.FaceletException;
 import java.io.IOException;
 import java.net.URL;
+import javax.faces.view.facelets.FaceletContext;
 
 /**
  * FaceletFactory for producing Facelets relative to the context of the underlying implementation.
@@ -60,6 +61,23 @@ public abstract class FaceletFactory
      * @throws ELException
      */
     public abstract Facelet getFacelet(URL url) throws IOException, FaceletException, FacesException, ELException;
+
+    /**
+     * Create a Facelet from the passed URL, but take into account the context. This method is
+     * useful in cases where the facelet instance must replace the one in the cache based on 
+     * the context, instead take the one from the cache, like for example when the EL expression
+     * cache is used.
+     * 
+     * @param url
+     *            source url
+     * @return Facelet instance
+     * @throws IOException
+     * @throws FaceletException
+     * @throws FacesException
+     * @throws ELException
+     */
+    public abstract Facelet getFacelet(FaceletContext ctx, URL url) 
+        throws IOException, FaceletException, FacesException, ELException;    
     
     /**
      * Return a Facelet instance as specified by the file at the passed URI. The returned facelet is used

Modified: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/TemplateContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/TemplateContext.java?rev=1470662&r1=1470661&r2=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/TemplateContext.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/TemplateContext.java Mon Apr 22 19:04:45 2013
@@ -20,6 +20,7 @@ package org.apache.myfaces.view.facelets
 
 import java.io.IOException;
 import java.util.Map;
+import java.util.Set;
 
 import javax.el.ELException;
 import javax.el.ValueExpression;
@@ -140,4 +141,43 @@ public abstract class TemplateContext
      * @return
      */
     public abstract void setAllowCacheELExpressions(boolean cacheELExpressions);
+    
+    /**
+     * 
+     * @since 2.1.12
+     * @param key
+     * @return 
+     */
+    public abstract boolean containsParameter(String key);
+    
+    /**
+     * Return a set of the parameters known associated to this template context and/or
+     * template. This logic is used to detect which EL Expressions can be cached or not.
+     * 
+     * @since 2.1.12
+     * @return 
+     */
+    public abstract Set<String> getKnownParameters();
+    
+    /**
+     * 
+     * @since 2.1.12
+     * @param key
+     * @return 
+     */
+    public abstract boolean containsKnownParameter(String key);
+    
+    /**
+     * 
+     * @since 2.1.12
+     * @return 
+     */
+    public abstract boolean isKnownParametersEmpty();
+    
+    /**
+     * 
+     * @since 2.1.12
+     * @param knownParameters 
+     */
+    public abstract void addKnownParameters(String knownParameters);
 }

Modified: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/el/DefaultVariableMapper.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/el/DefaultVariableMapper.java?rev=1470662&r1=1470661&r2=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/el/DefaultVariableMapper.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/el/DefaultVariableMapper.java Mon Apr 22 19:04:45 2013
@@ -93,9 +93,10 @@ public final class DefaultVariableMapper
                 }
             }
             
-            if (_templateContext != null && !_templateContext.isParameterEmpty())
+            if (_templateContext != null)
             {
-                if (_templateContext.getParameterMap().containsKey(name))
+                if (!_templateContext.isParameterEmpty() &&
+                    _templateContext.containsParameter(name))
                 {
                     returnValue = _templateContext.getParameter(name);
                     if (_trackResolveVariables)
@@ -104,6 +105,21 @@ public final class DefaultVariableMapper
                     }
                     return returnValue;
                 }
+                else if (!_templateContext.isKnownParametersEmpty() &&
+                    _templateContext.containsKnownParameter(name))
+                {
+                    // This part is the most important in alwaysRecompile EL cache hack.
+                    // The idea is maintain a list of the parameters used in a template,
+                    // and if the name to be resolved match one of the list, even if the
+                    // param was not set it is necessary to track it as variable resolved.
+                    // This will force create a new EL expression each time the view is
+                    // built, preserving ui:param and VariableMapper behavior, but allow
+                    // cache all expressions that are not related.
+                    if (_trackResolveVariables)
+                    {
+                        _variableResolved = true;
+                    }
+                }
             }
             
             if (_delegate != null)

Copied: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/CacheELFaceletCacheImpl.java (from r1468642, myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCacheImpl.java)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/CacheELFaceletCacheImpl.java?p2=myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/CacheELFaceletCacheImpl.java&p1=myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCacheImpl.java&r1=1468642&r2=1470662&rev=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCacheImpl.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/CacheELFaceletCacheImpl.java Mon Apr 22 19:04:45 2013
@@ -21,51 +21,59 @@ package org.apache.myfaces.view.facelets
 import java.io.IOException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
-import javax.faces.view.facelets.FaceletCache;
+import javax.faces.view.facelets.FaceletContext;
 import javax.faces.view.facelets.FaceletException;
 
 import org.apache.myfaces.shared.resource.ResourceLoaderUtils;
+import org.apache.myfaces.view.facelets.AbstractFaceletCache;
+import org.apache.myfaces.view.facelets.AbstractFaceletContext;
 import org.apache.myfaces.view.facelets.util.ParameterCheck;
 
 /**
- * TODO: Note MyFaces core has another type of Facelet for read composite component
- * metadata. The reason behind do this in MyFaces is to retrieve some information
- * related to insertChildren/insertFacet that can be used as metadata and use that
- * information later to do the hack for composite components using templates, instead
- * rely on component relocation. This is not handled by FaceletCache included here 
- * but in practice this should not be a problem, because the intention of this class
- * is handle Facelet instances created using custom ResourceResolver stuff, and 
- * usually those pages are for views, not for composite components. Even if that is
- * true, composite component metadata Facelet is smaller (only add cc:xxx stuff) that
- * the other ones used for views or the one used to apply the composite component
- * itself.  
+ * Extended MyFaces specific FaceletCache implementation that recompile
+ * facelet instance when a template context param is found.
  * 
  * @author Leonardo Uribe
  * @since 2.1.0
  *
  */
-class FaceletCacheImpl extends FaceletCache<DefaultFacelet>
+class CacheELFaceletCacheImpl extends AbstractFaceletCache<DefaultFacelet>
 {
 
     private static final long INFINITE_DELAY = -1;
     private static final long NO_CACHE_DELAY = 0;
     
-    private Map<String, DefaultFacelet> _facelets;
+    /**
+     * FaceletNode is necessary only here, because view metadata and 
+     * composite component metadata are special and does not allow use nested
+     * template tags. View metadata facelet trims everything outside f:metadata
+     * and composite component metadata only takes into account composite:xxx tags,
+     * ignoring ui:xxx tags.
+     */
+    private Map<String, FaceletNode> _facelets;
     
     private Map<String, DefaultFacelet> _viewMetadataFacelets;
-
+    
+    private Map<String, DefaultFacelet> _compositeComponentMetadataFacelets;
+    
     private long _refreshPeriod;
     
-    FaceletCacheImpl(long refreshPeriod)
+    CacheELFaceletCacheImpl(long refreshPeriod)
     {
         _refreshPeriod = refreshPeriod < 0 ? INFINITE_DELAY : refreshPeriod * 1000;
+
+        _facelets = new ConcurrentHashMap<String, FaceletNode>();
         
-        _facelets = new HashMap<String, DefaultFacelet>();
+        _viewMetadataFacelets = new ConcurrentHashMap<String, DefaultFacelet>();
         
-        _viewMetadataFacelets = new HashMap<String, DefaultFacelet>();
+        _compositeComponentMetadataFacelets = new ConcurrentHashMap<String, DefaultFacelet>();
     }
 
     @Override
@@ -75,19 +83,98 @@ class FaceletCacheImpl extends FaceletCa
         
         String key = url.toString();
         
-        DefaultFacelet f = _facelets.get(key);
+        FaceletNode node = _facelets.get(key);
+        DefaultFacelet f = node != null ? node.getFacelet() : null;
         
         if (f == null || this.needsToBeRefreshed(f))
         {
             //f = this._createFacelet(url);
+            Set<String> paramsSet = null;
+            if (node != null)
+            {
+                paramsSet = node.getParams();
+            }
+            f = getMemberFactory().newInstance(url);
+            if (_refreshPeriod != NO_CACHE_DELAY)
+            {
+                //Map<String, FaceletNode> newLoc = new HashMap<String, FaceletNode>(_facelets);
+                //newLoc.put(key, (paramsSet != null && !paramsSet.isEmpty()) ? 
+                //        new FaceletNode(f, paramsSet) : new FaceletNode(f) );
+                //_facelets = newLoc;
+                _facelets.put(key, (paramsSet != null && !paramsSet.isEmpty()) ? 
+                        new FaceletNode(f, paramsSet) : new FaceletNode(f) );
+            }
+        }
+        
+        return f;
+    }
+
+    @Override
+    public DefaultFacelet getFacelet(FaceletContext ctx, URL url) throws IOException
+    {
+        String key = url.toString();
+        
+        //1. Check that the current parameters on the template are known
+        //   for the template.
+        //2. If all current parameters are known return the template
+        //2. If some current parameter is not known, add the param(s) to the
+        //   template, register the known params in the template context and
+        //   recompile the facelet, to clean up al EL expressions at once.
+
+        FaceletNode node = _facelets.get(key);
+        DefaultFacelet f = (node != null) ? node.getFacelet() : null;
+        
+        Set<String> paramsSet = Collections.emptySet();
+        paramsSet = (node != null) ? node.getParams() : paramsSet;
+
+        AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
+        Set<String> knownParameters = actx.getTemplateContext().isKnownParametersEmpty() ?
+            (Set) Collections.emptySet() : actx.getTemplateContext().getKnownParameters();
+        
+        boolean create = false;
+        for (String paramKey : knownParameters)
+        {
+            if (!paramsSet.contains(paramKey))
+            {
+                create = true;
+                break;
+            }
+        }
+        
+        if (f == null || this.needsToBeRefreshed(f) || create)
+        {
+            //f = this._createFacelet(url);
             f = getMemberFactory().newInstance(url);
             if (_refreshPeriod != NO_CACHE_DELAY)
             {
-                Map<String, DefaultFacelet> newLoc = new HashMap<String, DefaultFacelet>(_facelets);
-                newLoc.put(key, f);
+                Map<String, FaceletNode> newLoc = new HashMap<String, FaceletNode>(_facelets);
+                if (!paramsSet.isEmpty()|| !knownParameters.isEmpty() )
+                {
+                    paramsSet = new HashSet(paramsSet);
+                    paramsSet.addAll(knownParameters);
+                    //newLoc.put(key, new FaceletNode(f, paramsSet));
+                    _facelets.put(key, new FaceletNode(f, paramsSet));
+                }
+                else
+                {
+                    //newLoc.put(key, new FaceletNode(f));
+                    _facelets.put(key, new FaceletNode(f));
+                }
                 _facelets = newLoc;
             }
         }
+
+        if (!paramsSet.isEmpty())
+        {
+            //actx.getTemplateContext().getKnownParameters().addAll(paramsSet);
+            for (String param : paramsSet)
+            {
+                if (!actx.getTemplateContext().containsKnownParameter(param))
+                {
+                    actx.getTemplateContext().addKnownParameters(param);
+                }
+            }
+        }
         
         return f;
     }
@@ -113,9 +200,10 @@ class FaceletCacheImpl extends FaceletCa
             f = getMetadataMemberFactory().newInstance(url);
             if (_refreshPeriod != NO_CACHE_DELAY)
             {
-                Map<String, DefaultFacelet> newLoc = new HashMap<String, DefaultFacelet>(_viewMetadataFacelets);
-                newLoc.put(key, f);
-                _viewMetadataFacelets = newLoc;
+                //Map<String, DefaultFacelet> newLoc = new HashMap<String, DefaultFacelet>(_viewMetadataFacelets);
+                //newLoc.put(key, f);
+                //_viewMetadataFacelets = newLoc;
+                _viewMetadataFacelets.put(key, f);
             }
         }
         
@@ -169,4 +257,85 @@ class FaceletCacheImpl extends FaceletCa
 
         return false;
     }
-}
+
+    @Override
+    public DefaultFacelet getCompositeComponentMetadataFacelet(URL url) throws IOException
+    {
+        ParameterCheck.notNull("url", url);
+
+        String key = url.toString();
+
+        DefaultFacelet f = _compositeComponentMetadataFacelets.get(key);
+
+        if (f == null || this.needsToBeRefreshed(f))
+        {
+            f = getCompositeComponentMetadataMemberFactory().newInstance(url);
+            if (_refreshPeriod != NO_CACHE_DELAY)
+            {
+                //Map<String, DefaultFacelet> newLoc
+                //        = new HashMap<String, DefaultFacelet>(_compositeComponentMetadataFacelets);
+                //newLoc.put(key, f);
+                //_compositeComponentMetadataFacelets = newLoc;
+                _compositeComponentMetadataFacelets.put(key, f);
+            }
+        }
+        return f;
+    }
+
+    @Override
+    public boolean isCompositeComponentMetadataFaceletCached(URL url)
+    {
+        return _compositeComponentMetadataFacelets.containsKey(url);
+    }
+    
+    private static class FaceletNode
+    {
+        private DefaultFacelet facelet;
+        private Set<String> params;
+
+        public FaceletNode(DefaultFacelet facelet)
+        {
+            this.facelet = facelet;
+            this.params = Collections.emptySet();
+        }
+        
+        public FaceletNode(DefaultFacelet facelet, Set<String> params)
+        {
+            this.facelet = facelet;
+            this.params = params;
+        }
+        
+        /**
+         * @return the facelet
+         */
+        public DefaultFacelet getFacelet()
+        {
+            return facelet;
+        }
+
+        /**
+         * @param facelet the facelet to set
+         */
+        public void setFacelet(DefaultFacelet facelet)
+        {
+            this.facelet = facelet;
+        }
+
+        /**
+         * @return the params
+         */
+        public Set<String> getParams()
+        {
+            return params;
+        }
+
+        /**
+         * @param params the params to set
+         */
+        public void setParams(Set<String> params)
+        {
+            this.params = params;
+        }
+        
+    }
+}
\ No newline at end of file

Modified: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFacelet.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFacelet.java?rev=1470662&r1=1470661&r2=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFacelet.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFacelet.java Mon Apr 22 19:04:45 2013
@@ -462,7 +462,7 @@ final class DefaultFacelet extends Abstr
     public void include(AbstractFaceletContext ctx, UIComponent parent, URL url) throws IOException, FacesException,
             FaceletException, ELException
     {
-        DefaultFacelet f = (DefaultFacelet) _factory.getFacelet(url);
+        DefaultFacelet f = (DefaultFacelet) _factory.getFacelet(ctx, url);
         f.include(ctx, parent);
     }
     

Modified: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletFactory.java?rev=1470662&r1=1470661&r2=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletFactory.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletFactory.java Mon Apr 22 19:04:45 2013
@@ -34,11 +34,13 @@ import javax.faces.FacesException;
 import javax.faces.FactoryFinder;
 import javax.faces.view.facelets.FaceletCache;
 import javax.faces.view.facelets.FaceletCacheFactory;
+import javax.faces.view.facelets.FaceletContext;
 import javax.faces.view.facelets.FaceletException;
 import javax.faces.view.facelets.FaceletHandler;
 import javax.faces.view.facelets.ResourceResolver;
 
 import org.apache.myfaces.shared.resource.ResourceLoaderUtils;
+import org.apache.myfaces.view.facelets.AbstractFaceletCache;
 import org.apache.myfaces.view.facelets.Facelet;
 import org.apache.myfaces.view.facelets.FaceletFactory;
 import org.apache.myfaces.view.facelets.compiler.Compiler;
@@ -75,6 +77,7 @@ public final class DefaultFaceletFactory
     private javax.faces.view.facelets.ResourceResolver _resolver;
     
     private FaceletCache<Facelet> _faceletCache;
+    private AbstractFaceletCache<Facelet> _abstractFaceletCache;
     
     public DefaultFaceletFactory(Compiler compiler, ResourceResolver resolver) throws IOException
     {
@@ -122,22 +125,55 @@ public final class DefaultFaceletFactory
             }
         };
         
-        // Note that FaceletCache.setMemberFactories method is protected, and this is the place where call
-        // this method has sense, because DefaultFaceletFactory is the responsible to create Facelet instances.
-        // The only way to do it is using reflection, and it has sense, because in this way it is possible to
-        // setup a java SecurityManager that prevents call this method (because it is protected, and to do that
-        // the code first check for "suppressAccessChecks" permission).
-        try
+        if (_faceletCache instanceof AbstractFaceletCache)
         {
-            Method setMemberFactoriesMethod = FaceletCache.class.getDeclaredMethod("setMemberFactories",
-                    new Class[]{FaceletCache.MemberFactory.class, FaceletCache.MemberFactory.class});
-            setMemberFactoriesMethod.setAccessible(true);
-            setMemberFactoriesMethod.invoke(_faceletCache, faceletFactory, viewMetadataFaceletFactory);
-        } 
-        catch (Exception e)
+            _abstractFaceletCache = (AbstractFaceletCache<Facelet>) _faceletCache;
+            
+            FaceletCache.MemberFactory<Facelet> compositeComponentMetadataFaceletFactory = 
+                new FaceletCache.MemberFactory<Facelet>()
+            {
+                public Facelet newInstance(URL url) throws IOException
+                {
+                    return _createCompositeComponentMetadataFacelet(url);
+                }
+            };
+
+            try
+            {
+                Method setMemberFactoriesMethod = AbstractFaceletCache.class.getDeclaredMethod("setMemberFactories",
+                        new Class[]{FaceletCache.MemberFactory.class, FaceletCache.MemberFactory.class, 
+                                    FaceletCache.MemberFactory.class});
+                setMemberFactoriesMethod.setAccessible(true);
+                setMemberFactoriesMethod.invoke(_faceletCache, faceletFactory, viewMetadataFaceletFactory, 
+                    compositeComponentMetadataFaceletFactory);
+            } 
+            catch (Exception e)
+            {
+                throw new FacesException(
+                    "Cannot call setMemberFactories method, Initialization of FaceletCache failed.",
+                                         e);
+            }   
+        }
+        else
         {
-            throw new FacesException("Cannot call setMemberFactories method, Initialization of FaceletCache failed.",
-                                     e);
+            // Note that FaceletCache.setMemberFactories method is protected, and this is the place where call
+            // this method has sense, because DefaultFaceletFactory is the responsible to create Facelet instances.
+            // The only way to do it is using reflection, and it has sense, because in this way it is possible to
+            // setup a java SecurityManager that prevents call this method (because it is protected, and to do that
+            // the code first check for "suppressAccessChecks" permission).
+            try
+            {
+                Method setMemberFactoriesMethod = FaceletCache.class.getDeclaredMethod("setMemberFactories",
+                        new Class[]{FaceletCache.MemberFactory.class, FaceletCache.MemberFactory.class});
+                setMemberFactoriesMethod.setAccessible(true);
+                setMemberFactoriesMethod.invoke(_faceletCache, faceletFactory, viewMetadataFaceletFactory);
+            } 
+            catch (Exception e)
+            {
+                throw new FacesException(
+                    "Cannot call setMemberFactories method, Initialization of FaceletCache failed.",
+                                         e);
+            }            
         }
 
         if (log.isLoggable(Level.FINE))
@@ -162,6 +198,7 @@ public final class DefaultFaceletFactory
      * 
      * @see org.apache.myfaces.view.facelets.FaceletFactory#getFacelet(java.lang.String)
      */
+    @Override
     public Facelet getFacelet(String uri) throws IOException, FaceletException, FacesException, ELException
     {
         URL url = (URL) _relativeLocations.get(uri);
@@ -194,10 +231,26 @@ public final class DefaultFaceletFactory
      * @throws FacesException
      * @throws ELException
      */
+    @Override
     public Facelet getFacelet(URL url) throws IOException, FaceletException, FacesException, ELException
     {
         return _faceletCache.getFacelet(url);
     }
+    
+    
+    @Override
+    public Facelet getFacelet(FaceletContext ctx, URL url) 
+            throws IOException, FaceletException, FacesException, ELException
+    {
+        if (_abstractFaceletCache != null)
+        {
+            return _abstractFaceletCache.getFacelet(ctx, url);
+        }
+        else
+        {
+            return _faceletCache.getFacelet(url);
+        }
+    }
 
     public long getRefreshPeriod()
     {
@@ -408,7 +461,14 @@ public final class DefaultFaceletFactory
     public Facelet getViewMetadataFacelet(URL url) throws IOException,
             FaceletException, FacesException, ELException
     {
-        return _faceletCache.getViewMetadataFacelet(url);
+        if (_abstractFaceletCache != null)
+        {
+            return _abstractFaceletCache.getViewMetadataFacelet(url);
+        }
+        else
+        {
+            return _faceletCache.getViewMetadataFacelet(url);
+        }
     }
     
     /**
@@ -444,25 +504,31 @@ public final class DefaultFaceletFactory
     public Facelet getCompositeComponentMetadataFacelet(URL url) throws IOException,
             FaceletException, FacesException, ELException
     {
-        ParameterCheck.notNull("url", url);
-        
-        String key = url.toString();
-        
-        DefaultFacelet f = _compositeComponentMetadataFacelets.get(key);
-        
-        if (f == null || this.needsToBeRefreshed(f))
+        if (_abstractFaceletCache != null)
         {
-            f = this._createCompositeComponentMetadataFacelet(url);
-            if (_refreshPeriod != NO_CACHE_DELAY)
+            return _abstractFaceletCache.getCompositeComponentMetadataFacelet(url);
+        }
+        else
+        {
+            ParameterCheck.notNull("url", url);
+
+            String key = url.toString();
+
+            DefaultFacelet f = _compositeComponentMetadataFacelets.get(key);
+
+            if (f == null || this.needsToBeRefreshed(f))
             {
-                Map<String, DefaultFacelet> newLoc
-                        = new HashMap<String, DefaultFacelet>(_compositeComponentMetadataFacelets);
-                newLoc.put(key, f);
-                _compositeComponentMetadataFacelets = newLoc;
+                f = this._createCompositeComponentMetadataFacelet(url);
+                if (_refreshPeriod != NO_CACHE_DELAY)
+                {
+                    Map<String, DefaultFacelet> newLoc
+                            = new HashMap<String, DefaultFacelet>(_compositeComponentMetadataFacelets);
+                    newLoc.put(key, f);
+                    _compositeComponentMetadataFacelets = newLoc;
+                }
             }
+            return f;
         }
-        
-        return f;
     }
 
     /**

Modified: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCacheFactoryImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCacheFactoryImpl.java?rev=1470662&r1=1470661&r2=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCacheFactoryImpl.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCacheFactoryImpl.java Mon Apr 22 19:04:45 2013
@@ -25,6 +25,7 @@ import javax.faces.view.facelets.Facelet
 import javax.faces.view.facelets.FaceletCacheFactory;
 
 import org.apache.myfaces.shared.util.WebConfigParamUtils;
+import org.apache.myfaces.view.facelets.ELExpressionCacheMode;
 import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
 
 /**
@@ -59,7 +60,19 @@ public class FaceletCacheFactoryImpl ext
                     FaceletViewDeclarationLanguage.DEFAULT_REFRESH_PERIOD);
         }
         
-        return new FaceletCacheImpl(refreshPeriod);
+        String elMode = WebConfigParamUtils.getStringInitParameter(
+                    context.getExternalContext(),
+                    FaceletCompositionContextImpl.INIT_PARAM_CACHE_EL_EXPRESSIONS, 
+                        ELExpressionCacheMode.noCache.name());
+        
+        if (ELExpressionCacheMode.alwaysRecompile.toString().equals(elMode))
+        {
+            return new CacheELFaceletCacheImpl(refreshPeriod);
+        }
+        else
+        {
+            return new FaceletCacheImpl(refreshPeriod);
+        }
     }
 
 }

Modified: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/TemplateContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/TemplateContextImpl.java?rev=1470662&r1=1470661&r2=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/TemplateContextImpl.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/TemplateContextImpl.java Mon Apr 22 19:04:45 2013
@@ -19,12 +19,12 @@
 package org.apache.myfaces.view.facelets.impl;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
@@ -63,18 +63,22 @@ public class TemplateContextImpl extends
      */
     private static final PageContext INITIAL_PAGE_CONTEXT = new InitialPageContext();
     
-    private final LinkedList<TemplateManagerImpl> _clients;
+    private final List<TemplateManagerImpl> _clients;
     
     private TemplateManager _compositeComponentClient;
     
     private TemplateManagerImpl _lastClient;
     
     private boolean _isCacheELExpressions;
+    
+    private final TemplateClientAttributeMap _templateClientAttributeMap;
+    
+    private final TemplateClientKnownParameterMap _templateClientKnownParameterMap;
 
     public TemplateContextImpl()
     {
         super();
-        _clients = new LinkedList<TemplateManagerImpl>();
+        _clients = new ArrayList<TemplateManagerImpl>(4);
         // Parameters registered using ui:param now are bound to template manager instances, because
         // it should follow the same rules as template clients registered here. For example, to resolve
         // params on nested ui:decorate and ui:composition the same rules applies than for ui:define and
@@ -82,36 +86,38 @@ public class TemplateContextImpl extends
         // page context, so when a new context is added (like in a ui:include), all params registered go 
         // to this manager. 
         _clients.add(new TemplateManagerImpl(null, INITIAL_TEMPLATE_CLIENT, true, INITIAL_PAGE_CONTEXT));
-        _lastClient = _clients.getFirst();
+        _lastClient = _clients.get(0); //_clients.getFirst();
         _isCacheELExpressions = true;
+        _templateClientAttributeMap = new TemplateClientAttributeMap();
+        _templateClientKnownParameterMap = new TemplateClientKnownParameterMap();
     }
 
     @Override
     public TemplateManager popClient(final AbstractFaceletContext actx)
     {
         _lastClient = null;
-        return _clients.removeFirst();
+        return _clients.remove(0);
     }
 
     @Override
     public void pushClient(final AbstractFaceletContext actx, final AbstractFacelet owner, final TemplateClient client)
     {
-        _clients.addFirst(new TemplateManagerImpl(owner, client, true, actx.getPageContext()));
-        _lastClient = _clients.getFirst();
+        _clients.add(0, new TemplateManagerImpl(owner, client, true, actx.getPageContext()));
+        _lastClient = _clients.get(0);
     }
 
     public TemplateManager popExtendedClient(final AbstractFaceletContext actx)
     {
         _lastClient = null;
-        return _clients.removeLast();
+        return _clients.remove(_clients.size()-1);
     }
     
     @Override
     public void extendClient(final AbstractFaceletContext actx, final AbstractFacelet owner,
                              final TemplateClient client)
     {
-        _clients.addLast(new TemplateManagerImpl(owner, client, false, actx.getPageContext()));
-        _lastClient = _clients.getLast();
+        _clients.add(new TemplateManagerImpl(owner, client, false, actx.getPageContext()));
+        _lastClient = _clients.get(_clients.size()-1);
     }
 
     @Override
@@ -120,10 +126,9 @@ public class TemplateContextImpl extends
     {
         boolean found = false;
         TemplateManager client;
-        Iterator<TemplateManagerImpl> itr = _clients.iterator();
-        while (itr.hasNext() && !found)
+        for (int i = 0; i < _clients.size() && !found; i++)
         {
-            client = itr.next();
+            client = _clients.get(i);
             if (client.equals(owner))
             {
                 continue;
@@ -146,6 +151,8 @@ public class TemplateContextImpl extends
         private final PageContext _pageContext;
         
         private Map<String, ValueExpression> _parameters = null;
+        
+        private Set<String> _knownParameters;
 
         public TemplateManagerImpl(AbstractFacelet owner, TemplateClient target,
                 boolean root, PageContext pageContext)
@@ -206,11 +213,25 @@ public class TemplateContextImpl extends
             return _parameters;
         }
         
-        public boolean isParamentersMapEmpty()
+        public boolean isParametersMapEmpty()
         {
             return _parameters == null ? true : _parameters.isEmpty();
         }
 
+        public Set<String> getKnownParameters()
+        {
+            if (_knownParameters == null)
+            {
+                _knownParameters = new HashSet<String>(4);
+            }
+            return _knownParameters;
+        }
+        
+        public boolean isKnownParametersEmpty()
+        {
+            return _knownParameters == null ? true : _knownParameters.isEmpty();
+        }
+        
         public boolean equals(Object o)
         {
             if (this._owner != null)
@@ -254,11 +275,10 @@ public class TemplateContextImpl extends
     public ValueExpression getParameter(String key)
     {
         TemplateManagerImpl client;
-        Iterator<TemplateManagerImpl> itr = _clients.iterator();
-        while (itr.hasNext())
+        for (int i = 0; i < _clients.size(); i++)
         {
-            client = itr.next();
-            if (!client.isParamentersMapEmpty() &&
+            client = _clients.get(i);
+            if (!client.isParametersMapEmpty() &&
                  client.getParametersMap().containsKey(key))
             {
                 return client.getParametersMap().get(key);
@@ -268,11 +288,28 @@ public class TemplateContextImpl extends
     }
 
     @Override
+    public boolean containsParameter(String key)
+    {
+        TemplateManagerImpl client;
+        for (int i = 0; i < _clients.size(); i++)
+        {
+            client = _clients.get(i);
+            if (!client.isParametersMapEmpty() &&
+                client.getParametersMap().containsKey(key))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
     public void setParameter(String key, ValueExpression value)
     {
         if (_lastClient != null)
         {
             _lastClient.getParametersMap().put(key, value);
+            _lastClient.getKnownParameters().add(key);
         }
     }
 
@@ -280,11 +317,10 @@ public class TemplateContextImpl extends
     public boolean isParameterEmpty()
     {
         TemplateManagerImpl client;
-        Iterator<TemplateManagerImpl> itr = _clients.iterator();
-        while (itr.hasNext())
+        for (int i = 0; i < _clients.size(); i++)
         {
-            client = itr.next();
-            if (!client.isParamentersMapEmpty())
+            client = _clients.get(i);
+            if (!client.isParametersMapEmpty())
             {
                 return false;
             }
@@ -294,7 +330,50 @@ public class TemplateContextImpl extends
     
     public Map<String, ValueExpression> getParameterMap()
     {
-        return new TemplateClientAttributeMap();
+        return _templateClientAttributeMap;
+    }
+    
+    public boolean isKnownParametersEmpty()
+    {
+        TemplateManagerImpl client;
+        for (int i = 0; i < _clients.size(); i++)
+        {
+            client = _clients.get(i);
+            if (!client.isKnownParametersEmpty())
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    public Set<String> getKnownParameters()
+    {
+        return _templateClientKnownParameterMap.keySet();
+    }
+    
+    @Override
+    public boolean containsKnownParameter(String key)
+    {
+        TemplateManagerImpl client;
+        for (int i = 0; i < _clients.size(); i++)
+        {
+            client = _clients.get(i);
+            if (client.getKnownParameters().contains(key))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    @Override
+    public void addKnownParameters(String key)
+    {
+        if (_lastClient != null)
+        {        
+            _lastClient.getKnownParameters().add(key);
+        }
     }
 
     private final class TemplateClientAttributeMap extends AbstractAttributeMap<ValueExpression>
@@ -308,11 +387,10 @@ public class TemplateContextImpl extends
         protected ValueExpression getAttribute(String key)
         {
             TemplateManagerImpl client;
-            Iterator<TemplateManagerImpl> itr = _clients.iterator();
-            while (itr.hasNext())
+            for (int i = 0; i < _clients.size(); i++)
             {
-                client = itr.next();
-                if (!client.isParamentersMapEmpty() &&
+                client = _clients.get(i);
+                if (!client.isParametersMapEmpty() &&
                      client.getParametersMap().containsKey(key))
                 {
                     return client.getParametersMap().get(key);
@@ -324,19 +402,14 @@ public class TemplateContextImpl extends
         @Override
         protected void setAttribute(String key, ValueExpression value)
         {
-            if (_lastClient != null)
-            {
-                _lastClient.getParametersMap().put(key, value);
-            }
+            //Use the parent methods.
+            throw new UnsupportedOperationException();
         }
 
         @Override
         protected void removeAttribute(String key)
         {
-            if (_lastClient != null)
-            {
-                _lastClient.getParametersMap().remove(key);
-            }
+            throw new UnsupportedOperationException();
         }
 
         @Override
@@ -344,11 +417,10 @@ public class TemplateContextImpl extends
         {
             Set<String> attributeNames = new HashSet<String>();
             TemplateManagerImpl client;
-            Iterator<TemplateManagerImpl> itr = _clients.iterator();
-            while (itr.hasNext())
+            for (int i = 0; i < _clients.size(); i++)
             {
-                client = itr.next();
-                if (!client.isParamentersMapEmpty())
+                client = _clients.get(i);
+                if (!client.isParametersMapEmpty())
                 {
                     attributeNames.addAll(client.getParametersMap().keySet());
                 }
@@ -385,6 +457,59 @@ public class TemplateContextImpl extends
         }
     }
     
+    private final class TemplateClientKnownParameterMap extends AbstractAttributeMap<Boolean>
+    {
+
+        public TemplateClientKnownParameterMap()
+        {
+        }
+        
+        @Override
+        protected Boolean getAttribute(String key)
+        {
+            TemplateManagerImpl client;
+            for (int i = 0; i < _clients.size(); i++)
+            {
+                client = _clients.get(i);
+                if (!client.isKnownParametersEmpty() &&
+                     client.getKnownParameters().contains(key))
+                {
+                    return Boolean.TRUE;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        protected void setAttribute(String key, Boolean value)
+        {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected void removeAttribute(String key)
+        {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected Enumeration<String> getAttributeNames()
+        {
+            Set<String> attributeNames = new HashSet<String>();
+            TemplateManagerImpl client;
+            for (int i = 0; i < _clients.size(); i++)
+            {
+                client = _clients.get(i);
+                if (!client.isParametersMapEmpty())
+                {
+                    attributeNames.addAll(client.getParametersMap().keySet());
+                }
+            }
+            
+            return new ParameterNameEnumeration(attributeNames.toArray(new String[attributeNames.size()]));
+        }
+    }    
+    
     /**
      * This is just a dummy template client that does nothing that is added by default
      * for each template context 
@@ -446,5 +571,4 @@ public class TemplateContextImpl extends
         _isCacheELExpressions = cacheELExpressions;
     }
     
-    
 }

Modified: myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/UserTagHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/UserTagHandler.java?rev=1470662&r1=1470661&r2=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/UserTagHandler.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/UserTagHandler.java Mon Apr 22 19:04:45 2013
@@ -37,6 +37,7 @@ import javax.faces.view.facelets.TagExce
 import javax.faces.view.facelets.TagHandler;
 
 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
+import org.apache.myfaces.view.facelets.ELExpressionCacheMode;
 import org.apache.myfaces.view.facelets.TemplateClient;
 import org.apache.myfaces.view.facelets.TemplateContext;
 import org.apache.myfaces.view.facelets.impl.TemplateContextImpl;
@@ -111,6 +112,7 @@ final class UserTagHandler extends TagHa
                 }
             }
             actx.pushTemplateContext(new TemplateContextImpl());
+            actx.pushClient(this);
             if (this._vars.length > 0)
             {
                 for (int i = 0; i < this._vars.length; i++)
@@ -118,9 +120,12 @@ final class UserTagHandler extends TagHa
                     ((AbstractFaceletContext) ctx).getTemplateContext().setParameter(names[i], values[i]);
                 }
             }
-            //Disable caching always, even in 'always' mode
-            actx.getTemplateContext().setAllowCacheELExpressions(false);
-            actx.pushClient(this);
+            // Disable caching always, even in 'always' mode
+            // The only mode that can support EL caching in this condition is alwaysRedirect.
+            if (!ELExpressionCacheMode.alwaysRecompile.equals(actx.getELExpressionCacheMode()))
+            {
+                actx.getTemplateContext().setAllowCacheELExpressions(false);
+            }
             ctx.includeFacelet(parent, this._location);
         }
         catch (FileNotFoundException e)

Added: myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/el/CacheELExpressionsAlwaysRecompileTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/el/CacheELExpressionsAlwaysRecompileTestCase.java?rev=1470662&view=auto
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/el/CacheELExpressionsAlwaysRecompileTestCase.java (added)
+++ myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/el/CacheELExpressionsAlwaysRecompileTestCase.java Mon Apr 22 19:04:45 2013
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2013 The Apache Software Foundation.
+ *
+ * Licensed 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.io.StringWriter;
+import javax.el.ExpressionFactory;
+import javax.faces.component.UIViewRoot;
+import org.apache.myfaces.test.mock.MockResponseWriter;
+import org.apache.myfaces.view.facelets.ELExpressionCacheMode;
+import org.apache.myfaces.view.facelets.FaceletTestCase;
+import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
+import org.apache.myfaces.view.facelets.impl.FaceletCompositionContextImpl;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ * @author lu4242
+ */
+public class CacheELExpressionsAlwaysRecompileTestCase extends FaceletTestCase
+{
+    @Override
+    protected void setUpServletObjects() throws Exception
+    {
+        super.setUpServletObjects();
+        servletContext.addInitParameter(FaceletCompositionContextImpl.INIT_PARAM_CACHE_EL_EXPRESSIONS,
+            ELExpressionCacheMode.alwaysRecompile.toString());
+        servletContext.addInitParameter(FaceletViewDeclarationLanguage.PARAM_SKIP_COMMENTS, "true");
+        servletContext.addInitParameter(FaceletViewDeclarationLanguage.PARAM_LIBRARIES, "/user.taglib.xml");
+    }
+    
+    @Override
+    protected ExpressionFactory createExpressionFactory()
+    {
+        return new org.apache.el.ExpressionFactoryImpl();
+    }
+    
+    @Test
+    public void testUIParamCaching1() throws Exception
+    {
+        UIViewRoot root = facesContext.getViewRoot();
+        vdl.buildView(facesContext, root, "uiparamcache1.xhtml");
+
+        StringWriter sw = new StringWriter();
+        MockResponseWriter mrw = new MockResponseWriter(sw);
+        facesContext.setResponseWriter(mrw);
+        
+        root.encodeAll(facesContext);
+        sw.flush();
+        Assert.assertTrue(sw.toString().contains("ALFA"));
+        Assert.assertTrue(sw.toString().contains("BETA"));
+        Assert.assertTrue(sw.toString().contains("GAMMA"));
+        Assert.assertTrue(sw.toString().contains("OMEGA"));
+    }
+    
+    @Test
+    public void testUserTagCaching1() throws Exception
+    {
+        UIViewRoot root = facesContext.getViewRoot();
+        vdl.buildView(facesContext, root, "usertagtest1.xhtml");
+
+        StringWriter sw = new StringWriter();
+        MockResponseWriter mrw = new MockResponseWriter(sw);
+        facesContext.setResponseWriter(mrw);
+        
+        root.encodeAll(facesContext);
+        sw.flush();
+        Assert.assertTrue(sw.toString().contains("ALFA"));
+        Assert.assertTrue(sw.toString().contains("BETA"));
+        Assert.assertTrue(sw.toString().contains("GAMMA"));
+        Assert.assertTrue(sw.toString().contains("OMEGA"));
+    }
+
+    @Test
+    public void testUIParamIncludeCaching1() throws Exception
+    {
+        UIViewRoot root = facesContext.getViewRoot();
+        vdl.buildView(facesContext, root, "includetagtest1.xhtml");
+
+        StringWriter sw = new StringWriter();
+        MockResponseWriter mrw = new MockResponseWriter(sw);
+        facesContext.setResponseWriter(mrw);
+        
+        root.encodeAll(facesContext);
+        sw.flush();
+        Assert.assertTrue(sw.toString().contains("ALFA"));
+        Assert.assertTrue(sw.toString().contains("BETA"));
+        Assert.assertTrue(sw.toString().contains("GAMMA"));
+        Assert.assertTrue(sw.toString().contains("OMEGA"));
+    }
+}

Propchange: myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/el/CacheELExpressionsAlwaysRecompileTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/tag/ui/IncludeParamTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/tag/ui/IncludeParamTestCase.java?rev=1470662&r1=1470661&r2=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/tag/ui/IncludeParamTestCase.java (original)
+++ myfaces/core/branches/2.1.x/impl/src/test/java/org/apache/myfaces/view/facelets/tag/ui/IncludeParamTestCase.java Mon Apr 22 19:04:45 2013
@@ -32,7 +32,9 @@ import org.apache.myfaces.renderkit.html
 import org.apache.myfaces.renderkit.html.HtmlCompositeFacetRenderer;
 import org.apache.myfaces.renderkit.html.HtmlTextRenderer;
 import org.apache.myfaces.test.mock.MockExternalContext;
+import org.apache.myfaces.view.facelets.ELExpressionCacheMode;
 import org.apache.myfaces.view.facelets.FaceletTestCase;
+import org.apache.myfaces.view.facelets.impl.FaceletCompositionContextImpl;
 import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
 import org.apache.myfaces.view.facelets.util.FastWriter;
 import org.junit.Assert;
@@ -77,7 +79,7 @@ public class IncludeParamTestCase extend
         // handle VariableMapper stuff properly and ui:param logic will not work
         return new org.apache.el.ExpressionFactoryImpl();
     }
-    
+
     @Test
     public void testCaching() throws Exception
     {

Copied: myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/includetagtest1.xhtml (from r1468642, myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1.xhtml)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/includetagtest1.xhtml?p2=myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/includetagtest1.xhtml&p1=myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1.xhtml&r1=1468642&r2=1470662&rev=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1.xhtml (original)
+++ myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/includetagtest1.xhtml Mon Apr 22 19:04:45 2013
@@ -24,10 +24,18 @@
       xmlns:user="http://myfaces.apache.org/user">
 <body>
 <ui:composition>
-    <user:usertagtest1 var1="value1" var2="value2" var3="value3">
-        <h:outputText value="#{var2}"/>
-    </user:usertagtest1>
-    <h:outputText value="#{var3}"/>
+    <ui:include src="uiparamcache1_1.xhtml">
+    </ui:include>
+    <ui:include src="uiparamcache1_1.xhtml">
+        <ui:param name="param1" value="ALFA"/>
+    </ui:include>  
+    <ui:include src="uiparamcache1_1.xhtml">
+        <ui:param name="param2" value="BETA"/>
+    </ui:include>
+    <ui:include src="uiparamcache1_1.xhtml">
+        <ui:param name="param1" value="GAMMA"/>
+        <ui:param name="param2" value="OMEGA"/>
+    </ui:include>
 </ui:composition>
 </body>
 </html>

Copied: myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/user.taglib.xml (from r1468642, myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/user.taglib.xml)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/user.taglib.xml?p2=myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/user.taglib.xml&p1=myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/user.taglib.xml&r1=1468642&r2=1470662&rev=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/user.taglib.xml (original)
+++ myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/user.taglib.xml Mon Apr 22 19:04:45 2013
@@ -29,14 +29,4 @@
         <source>usertagtest1_1.xhtml</source>
     </tag>
 
-    <tag>
-        <tag-name>usertagtest2_1</tag-name>
-        <source>usertagtest2_1.xhtml</source>
-    </tag>
-
-    <tag>
-        <tag-name>usertagtest2_2</tag-name>
-        <source>usertagtest2_2.xhtml</source>
-    </tag>
-
 </facelet-taglib>

Copied: myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1.xhtml (from r1468642, myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1.xhtml)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1.xhtml?p2=myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1.xhtml&p1=myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1.xhtml&r1=1468642&r2=1470662&rev=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1.xhtml (original)
+++ myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1.xhtml Mon Apr 22 19:04:45 2013
@@ -24,10 +24,12 @@
       xmlns:user="http://myfaces.apache.org/user">
 <body>
 <ui:composition>
-    <user:usertagtest1 var1="value1" var2="value2" var3="value3">
-        <h:outputText value="#{var2}"/>
+    <user:usertagtest1 var1="ALFA" id="comp1">
+    </user:usertagtest1>
+    <user:usertagtest1 var2="BETA" id="comp2">
+    </user:usertagtest1>
+    <user:usertagtest1 var1="GAMMA" var2="OMEGA" id="comp3">
     </user:usertagtest1>
-    <h:outputText value="#{var3}"/>
 </ui:composition>
 </body>
 </html>

Copied: myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1_1.xhtml (from r1468642, myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1_1.xhtml)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1_1.xhtml?p2=myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1_1.xhtml&p1=myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1_1.xhtml&r1=1468642&r2=1470662&rev=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1_1.xhtml (original)
+++ myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1_1.xhtml Mon Apr 22 19:04:45 2013
@@ -23,7 +23,9 @@
       xmlns:c="http://java.sun.com/jsp/jstl/core">
 <body>
 <ui:composition>
-    <h:outputText value="#{var1}"/>
+    <h:outputText id="#{id}_1" value="#{var1}"/>
+    <ui:decorate template="/usertagtest1_2.xhtml"/>
+    <h:outputText id="#{id}_3" value="#{' hello '}"/>
 </ui:composition>
 </body>
 </html>

Copied: myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1_2.xhtml (from r1468642, myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1_1.xhtml)
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1_2.xhtml?p2=myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1_2.xhtml&p1=myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1_1.xhtml&r1=1468642&r2=1470662&rev=1470662&view=diff
==============================================================================
--- myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/ui/usertagtest1_1.xhtml (original)
+++ myfaces/core/branches/2.1.x/impl/src/test/resources/org/apache/myfaces/view/facelets/el/usertagtest1_2.xhtml Mon Apr 22 19:04:45 2013
@@ -22,8 +22,12 @@
       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:c="http://java.sun.com/jsp/jstl/core">
 <body>
+<!-- In this case, it is supposed the params id and var2 
+comes from the parent TemplateContext, so in this case
+the facelet must be recompiled and the EL Expressions
+containing some of these parameters will not be cached. -->
 <ui:composition>
-    <h:outputText value="#{var1}"/>
+    <h:outputText id="#{id}_2" value="#{var2}"/>
 </ui:composition>
 </body>
 </html>