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 2011/06/16 20:01:26 UTC

svn commit: r1136573 - in /myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets: ./ el/ impl/ tag/ tag/jstl/core/ tag/ui/

Author: lu4242
Date: Thu Jun 16 18:01:26 2011
New Revision: 1136573

URL: http://svn.apache.org/viewvc?rev=1136573&view=rev
Log:
MYFACES-3160 [PERF] TagAttributeImpl part II: object allocations (cache ELExpressions)

Added:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/ELExpressionCacheMode.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/VariableMapperBase.java
Modified:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletContext.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/PageContext.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/TemplateContext.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/DefaultVariableMapper.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/VariableMapperWrapper.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletContext.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/PageContextImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/TemplateContextImpl.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/UserTagHandler.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/SetHandler.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/ui/ParamHandler.java

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletContext.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletContext.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/AbstractFaceletContext.java Thu Jun 16 18:01:26 2011
@@ -227,4 +227,50 @@ public abstract class AbstractFaceletCon
     {
         return null;
     }
+    
+    /**
+     * Check if a variable has been resolved by this variable mapper
+     * or any parent "facelets contextual" variable mapper.
+     * 
+     * @return
+     * @since 2.0.8
+     */
+    public boolean isAnyFaceletsVariableResolved()
+    {
+        return true;
+    }
+    
+    public boolean isAllowCacheELExpressions()
+    {
+        return false;
+    }
+    
+    /**
+     * Indicates an expression will be resolved, so preparations
+     * should be done to detect if a contextual variable has been resolved.
+     * 
+     * @since 2.0.8
+     */
+    public void beforeConstructELExpression()
+    {
+    }
+    
+    /**
+     * Cleanup all initialization done for construct an EL Expression.
+     * 
+     * @since 2.0.8
+     */
+    public void afterConstructELExpression()
+    {
+    }
+
+    /**
+     * Return the mode used to decide whether to cache or not EL expressions
+     * 
+     * @since 2.0.8
+     */
+    public ELExpressionCacheMode getELExpressionCacheMode()
+    {
+        return ELExpressionCacheMode.noCache;
+    }
 }

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/ELExpressionCacheMode.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/ELExpressionCacheMode.java?rev=1136573&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/ELExpressionCacheMode.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/ELExpressionCacheMode.java Thu Jun 16 18:01:26 2011
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+public enum ELExpressionCacheMode
+{
+    /**
+     * Does not cache expressions.
+     */
+    noCache,
+    
+    /**
+     * Does not cache expressions on these cases:
+     * - A c:set tag with only var and value properties was used on the current page.
+     * - ui:param was used on the current template context
+     * - Inside user tags
+     * - An expression uses a variable resolved through VariableMapper
+     */
+    strict,
+
+    /**
+     * Does not cache expressions on these cases:
+     * - ui:param was used on the current template context
+     * - Inside user tags
+     * - An expression uses a variable resolved through VariableMapper
+     * 
+     * In this case, c:set is assumed to be always on the parent node.
+     */
+    allowCset,
+    
+    /**
+     * Does not cache expressions on these cases:
+     * - Inside user tags
+     * - An expression uses a variable resolved through VariableMapper
+     * 
+     * Note if ui:param is used, each template call should define the same
+     * param count, even if only just a few are used. 
+     */
+    always
+}

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java Thu Jun 16 18:01:26 2011
@@ -18,10 +18,8 @@
  */
 package org.apache.myfaces.view.facelets;
 
-import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 
 import javax.faces.component.UIComponent;
 import javax.faces.component.UniqueIdVendor;
@@ -333,5 +331,15 @@ abstract public class FaceletComposition
      * @return A value that could be useful to revert its effects.
      */
     public abstract Object removeMethodExpressionTargeted(UIComponent targetedComponent, String attributeName);
-
+    
+    /**
+     * Indicates if a EL Expression can be or not cached by facelets vdl.
+     * 
+     * @since 2.0.8
+     * @return
+     */
+    public ELExpressionCacheMode getELExpressionCacheMode()
+    {
+        return ELExpressionCacheMode.noCache;
+    }
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/PageContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/PageContext.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/PageContext.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/PageContext.java Thu Jun 16 18:01:26 2011
@@ -34,4 +34,9 @@ public abstract class PageContext
     public abstract Map<String, ValueExpression> getAttributes();
     
     public abstract int getAttributeCount();
+    
+    public abstract boolean isAllowCacheELExpressions();
+
+    public abstract void setAllowCacheELExpressions(boolean cacheELExpressions);
+
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/TemplateContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/TemplateContext.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/TemplateContext.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/TemplateContext.java Thu Jun 16 18:01:26 2011
@@ -126,4 +126,18 @@ public abstract class TemplateContext
      * @return
      */
     public abstract Map<String, ValueExpression> getParameterMap();
+
+    /**
+     * 
+     * @since 2.0.8
+     * @return
+     */
+    public abstract boolean isAllowCacheELExpressions();
+
+    /**
+     * 
+     * @since 2.0.8
+     * @return
+     */
+    public abstract void setAllowCacheELExpressions(boolean cacheELExpressions);
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/DefaultVariableMapper.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/DefaultVariableMapper.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/DefaultVariableMapper.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/DefaultVariableMapper.java Thu Jun 16 18:01:26 2011
@@ -37,7 +37,7 @@ import org.apache.myfaces.view.facelets.
  * @author Jacob Hookom
  * @version $Id: DefaultVariableMapper.java,v 1.3 2008/07/13 19:01:43 rlubke Exp $
  */
-public final class DefaultVariableMapper extends VariableMapper
+public final class DefaultVariableMapper extends VariableMapperBase
 {
     private Map<String, ValueExpression> _vars;
     
@@ -46,10 +46,16 @@ public final class DefaultVariableMapper
     private TemplateContext _templateContext;
     
     private VariableMapper _delegate;
+    
+    public boolean _trackResolveVariables;
+    
+    public boolean _variableResolved;
 
     public DefaultVariableMapper()
     {
         super();
+        _trackResolveVariables = false;
+        _variableResolved = false;
     }
 
     public DefaultVariableMapper(VariableMapper delegate)
@@ -69,26 +75,47 @@ public final class DefaultVariableMapper
         {
             returnValue = _vars.get(name);
         }
-        
-        if (returnValue == null && _pageContext != null)
+
+        //If the variable is not on the VariableMapper
+        if (returnValue == null)
         {
-            if (returnValue == null && _pageContext.getAttributeCount() > 0)
+            //Check on page and template context
+            if (_pageContext != null && _pageContext.getAttributeCount() > 0)
             {
-                returnValue = _pageContext.getAttributes().get(name);
+                if (_pageContext.getAttributes().containsKey(name))
+                {
+                    returnValue = _pageContext.getAttributes().get(name);
+                    if (_trackResolveVariables)
+                    {
+                        _variableResolved = true;
+                    }
+                    return returnValue;
+                }
             }
-        }
-        
-        if (returnValue == null && _templateContext != null)
-        {
-            if (returnValue == null && !_templateContext.isParameterEmpty())
+            
+            if (_templateContext != null && !_templateContext.isParameterEmpty())
             {
-                returnValue = _templateContext.getParameter(name);
+                if (_templateContext.getParameterMap().containsKey(name))
+                {
+                    returnValue = _templateContext.getParameter(name);
+                    if (_trackResolveVariables)
+                    {
+                        _variableResolved = true;
+                    }
+                    return returnValue;
+                }
             }
-        }        
-        
-        if (returnValue == null && _delegate != null)
+            
+            if (_delegate != null)
+            {
+                returnValue = _delegate.resolveVariable(name);
+            }
+        }
+        else if (_trackResolveVariables)
         {
-            returnValue = _delegate.resolveVariable(name);
+            // Is this code in a block that wants to cache 
+            // the resulting expression(s) and variable has been resolved?
+            _variableResolved = true;
         }
         
         return returnValue;
@@ -126,4 +153,32 @@ public final class DefaultVariableMapper
     {
         this._templateContext = templateContext;
     }
+
+    @Override
+    public boolean isAnyFaceletsVariableResolved()
+    {
+        if (_trackResolveVariables)
+        {
+            return _variableResolved;
+        }
+        else
+        {
+            //Force expression creation
+            return true;
+        }
+    }
+
+    @Override
+    public void beforeConstructELExpression()
+    {
+        _trackResolveVariables = true;
+        _variableResolved = false;
+    }
+
+    @Override
+    public void afterConstructELExpression()
+    {
+        _trackResolveVariables = false;
+        _variableResolved = false;
+    }
 }

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/VariableMapperBase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/VariableMapperBase.java?rev=1136573&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/VariableMapperBase.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/VariableMapperBase.java Thu Jun 16 18:01:26 2011
@@ -0,0 +1,54 @@
+/*
+ * 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.VariableMapper;
+
+/**
+ * Defines an interface to detect when an EL expression has been
+ * resolved by a facelets variable mapper and in that way allow cache it
+ * if it is possible. This class should be implemented by any 
+ * "facelets contextual" variable mapper.
+ * 
+ * @since 2.0.8
+ * @author Leonardo Uribe
+ *
+ */
+public abstract class VariableMapperBase extends VariableMapper
+{
+
+    /**
+     * Check if a variable has been resolved by this variable mapper
+     * or any parent "facelets contextual" variable mapper.
+     * 
+     * @return
+     */
+    public abstract boolean isAnyFaceletsVariableResolved();
+
+    /**
+     * Indicates an expression will be resolved, so preparations
+     * should be done to detect if a contextual variable has been resolved.
+     */
+    public abstract void beforeConstructELExpression();
+
+    /**
+     * Cleanup all initialization done.
+     */
+    public abstract void afterConstructELExpression();
+}

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/VariableMapperWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/VariableMapperWrapper.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/VariableMapperWrapper.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/el/VariableMapperWrapper.java Thu Jun 16 18:01:26 2011
@@ -24,6 +24,7 @@ import java.util.Map;
 import javax.el.ELException;
 import javax.el.ValueExpression;
 import javax.el.VariableMapper;
+import javax.faces.FacesWrapper;
 
 /**
  * Utility class for wrapping another VariableMapper with a new context, represented by a {@link java.util.Map Map}.
@@ -33,12 +34,20 @@ import javax.el.VariableMapper;
  * @author Jacob Hookom
  * @version $Id: VariableMapperWrapper.java,v 1.7 2008/07/13 19:01:43 rlubke Exp $
  */
-public final class VariableMapperWrapper extends VariableMapper
+public final class VariableMapperWrapper extends VariableMapperBase implements FacesWrapper<VariableMapper>
 {
 
     private final VariableMapper _target;
+    
+    private final VariableMapperBase _targetBase;
 
     private Map<String, ValueExpression> _vars;
+    
+    //private final boolean _checkTargetBase;
+    
+    public boolean _trackResolveVariables;
+    
+    public boolean _variableResolved;
 
     /**
      * 
@@ -47,6 +56,10 @@ public final class VariableMapperWrapper
     {
         super();
         _target = orig;
+        _targetBase = (orig instanceof VariableMapperBase) ? (VariableMapperBase) orig : null;
+        //_checkTargetBase = true;
+        _trackResolveVariables = false;
+        _variableResolved = false;
     }
 
     /**
@@ -62,6 +75,13 @@ public final class VariableMapperWrapper
             if (_vars != null)
             {
                 ve = (ValueExpression) _vars.get(variable);
+
+                // Is this code in a block that wants to cache 
+                // the resulting expression(s) and variable has been resolved?
+                if (_trackResolveVariables && ve != null)
+                {
+                    _variableResolved = true;
+                }
             }
             
             if (ve == null)
@@ -91,4 +111,77 @@ public final class VariableMapperWrapper
         
         return _vars.put(variable, expression);
     }
+
+    @Override
+    public boolean isAnyFaceletsVariableResolved()
+    {
+        if (_trackResolveVariables)
+        {
+            if (_variableResolved)
+            {
+                //Force EL creation!
+                return true;
+            }
+            else
+            {
+                //Otherwise check parent variable mapper 
+                //if (_checkTargetBase)
+                //{
+                    if (_targetBase != null)
+                    {
+                        return _targetBase.isAnyFaceletsVariableResolved();
+                    }
+                    else
+                    {
+                        // Another VariableMapper not extending from the base one was used. 
+                        // (that's the reason why _targetBase is null).
+                        // It is not possible to be sure the EL expression could use that mapper, 
+                        // so return true to force EL expression creation.
+                        return true;
+                    }
+                //}
+                //else
+                //{
+                    // If no check for targetBase is required, we are in a context that suppose there will not
+                    // be variables resolved that could affect the expressions. So return false, indicating
+                    // the resulting expression can be cached.
+                    //return false;
+                //}
+            }
+        }
+        else
+        {
+            // Force expression creation, because the call is outside caching block.
+            return true;
+        }
+    }
+
+    public VariableMapper getWrapped()
+    {
+        return _target;
+    }
+
+    @Override
+    public void beforeConstructELExpression()
+    {
+        _trackResolveVariables = true;
+        _variableResolved = false;
+        //if (_checkTargetBase && _targetBase != null)
+        if (_targetBase != null)
+        {
+            _targetBase.beforeConstructELExpression();
+        }
+    }
+
+    @Override
+    public void afterConstructELExpression()
+    {
+        //if (_checkTargetBase && _targetBase != null)
+        if (_targetBase != null)
+        {
+            _targetBase.afterConstructELExpression();
+        }
+        _trackResolveVariables = false;
+        _variableResolved = false;
+    }
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletContext.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletContext.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/DefaultFaceletContext.java Thu Jun 16 18:01:26 2011
@@ -45,12 +45,14 @@ import javax.faces.view.facelets.Facelet
 
 import org.apache.myfaces.view.facelets.AbstractFacelet;
 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
+import org.apache.myfaces.view.facelets.ELExpressionCacheMode;
 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
 import org.apache.myfaces.view.facelets.PageContext;
 import org.apache.myfaces.view.facelets.TemplateClient;
 import org.apache.myfaces.view.facelets.TemplateContext;
 import org.apache.myfaces.view.facelets.TemplateManager;
 import org.apache.myfaces.view.facelets.el.DefaultVariableMapper;
+import org.apache.myfaces.view.facelets.el.VariableMapperBase;
 import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
 
 /**
@@ -74,6 +76,7 @@ final class DefaultFaceletContext extend
 
     private VariableMapper _varMapper;
     private final DefaultVariableMapper _defaultVarMapper;
+    private VariableMapperBase _varMapperBase;
 
     private FunctionMapper _fnMapper;
 
@@ -92,6 +95,10 @@ final class DefaultFaceletContext extend
     private final List<TemplateContext> _isolatedTemplateContext;
     
     private int _currentTemplateContext;
+    
+    private ELExpressionCacheMode _elExpressionCacheMode;
+    
+    private boolean _isCacheELExpressions;
 
     private final List<PageContext> _isolatedPageContext;
     
@@ -106,6 +113,7 @@ final class DefaultFaceletContext extend
         _fnMapper = ctx._fnMapper;
         _varMapper = ctx._varMapper;
         _defaultVarMapper = ctx._defaultVarMapper;
+        _varMapperBase = ctx._varMapperBase;
         _faceletHierarchy = new ArrayList<AbstractFacelet>(ctx._faceletHierarchy
                 .size() + 1);
         _faceletHierarchy.addAll(ctx._faceletHierarchy);
@@ -140,6 +148,9 @@ final class DefaultFaceletContext extend
         _currentTemplateContext = ctx._currentTemplateContext;
         
         _isolatedPageContext = ctx._isolatedPageContext;
+        
+        _elExpressionCacheMode = ctx._elExpressionCacheMode;
+        _isCacheELExpressions = ctx._isCacheELExpressions;
 
         //Update FACELET_CONTEXT_KEY on FacesContext attribute map, to 
         //reflect the current facelet context instance
@@ -160,11 +171,13 @@ final class DefaultFaceletContext extend
         {
             _defaultVarMapper = new DefaultVariableMapper();
             _varMapper = _defaultVarMapper;
+            _varMapperBase = _defaultVarMapper;
         }
         else
         {
             _defaultVarMapper = new DefaultVariableMapper(_varMapper);
             _varMapper = _defaultVarMapper;
+            _varMapperBase = _defaultVarMapper;
         }
         
         _faceletHierarchy = new ArrayList<AbstractFacelet>(1);
@@ -178,6 +191,9 @@ final class DefaultFaceletContext extend
         _defaultVarMapper.setTemplateContext(_isolatedTemplateContext.get(_currentTemplateContext));
         
         _isolatedPageContext = new ArrayList<PageContext>(8);
+        
+        _elExpressionCacheMode = mctx.getELExpressionCacheMode();
+        _isCacheELExpressions = !ELExpressionCacheMode.noCache.equals(_elExpressionCacheMode);
 
         //Set FACELET_CONTEXT_KEY on FacesContext attribute map, to 
         //reflect the current facelet context instance
@@ -210,6 +226,7 @@ final class DefaultFaceletContext extend
     {
         // Assert.param("varMapper", varMapper);
         _varMapper = varMapper;
+        _varMapperBase = (_varMapper instanceof VariableMapperBase) ? (VariableMapperBase) varMapper : null;
     }
 
     /**
@@ -798,4 +815,43 @@ final class DefaultFaceletContext extend
     {
         return _mctx;
     }
+    
+    public boolean isAnyFaceletsVariableResolved()
+    {
+        //if (isAllowCacheELExpressions() && _varMapperBase != null)
+        if (_varMapperBase != null)
+        {
+            return _varMapperBase.isAnyFaceletsVariableResolved();
+        }
+        return true;
+    }
+    
+    public boolean isAllowCacheELExpressions()
+    {
+        return _isCacheELExpressions && getTemplateContext().isAllowCacheELExpressions() && getPageContext().isAllowCacheELExpressions();
+    }
+    
+    public void beforeConstructELExpression()
+    {
+        //if (isAllowCacheELExpressions() && _varMapperBase != null)
+        if (_varMapperBase != null)
+        {
+            _varMapperBase.beforeConstructELExpression();
+        }
+    }
+    
+    public void afterConstructELExpression()
+    {
+        //if (isAllowCacheELExpressions() && _varMapperBase != null)
+        if (_varMapperBase != null)
+        {
+            _varMapperBase.afterConstructELExpression();
+        }
+    }
+    
+    public ELExpressionCacheMode getELExpressionCacheMode()
+    {
+        return _elExpressionCacheMode;
+    }
+    
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java Thu Jun 16 18:01:26 2011
@@ -18,6 +18,9 @@
  */
 package org.apache.myfaces.view.facelets.impl;
 
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+import org.apache.myfaces.shared_impl.util.WebConfigParamUtils;
+import org.apache.myfaces.view.facelets.ELExpressionCacheMode;
 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
 import org.apache.myfaces.view.facelets.FaceletFactory;
 import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
@@ -41,6 +44,20 @@ import java.util.Map;
  */
 public class FaceletCompositionContextImpl extends FaceletCompositionContext
 {
+    /**
+     * Indicates if expressions generated by facelets should be cached or not. Default is noCache. There there are four modes:
+     * 
+     * <ul>
+     * <li>always: Only does not cache when expressions are inside user tags or the expression contains a variable resolved using VariableMapper</li>
+     * <li>allowCset: Like always, but does not allow cache when ui:param was used on the current template context</li>
+     * <li>strict: Like allowCset, but does not allow cache when c:set with var and value properties only is used on the current page context</li>
+     * <li>noCache: All expression are created each time the view is built</li>
+     * </ul>
+     * 
+     */
+    @JSFWebConfigParam(since="2.0.8", defaultValue="noCache", expectedValues="noCache, strict, allowCset, always")
+    public static final String INIT_PARAM_CACHE_EL_EXPRESSIONS = "org.apache.myfaces.CACHE_EL_EXPRESSIONS";
+    
     private FacesContext _facesContext;
     
     private FaceletFactory _factory;
@@ -62,6 +79,8 @@ public class FaceletCompositionContextIm
     private Boolean _refreshTransientBuildOnPSS;
     
     private Boolean _usingPSSOnThisView;
+    
+    private ELExpressionCacheMode _elExpressionCacheMode;
 
     private List<Map<String, UIComponent>> _componentsMarkedForDeletion;
     
@@ -346,6 +365,19 @@ public class FaceletCompositionContextIm
     }
 
     @Override
+    public ELExpressionCacheMode getELExpressionCacheMode()
+    {
+        if (_elExpressionCacheMode == null)
+        {
+            String value = WebConfigParamUtils.getStringInitParameter(
+                    _facesContext.getExternalContext(), INIT_PARAM_CACHE_EL_EXPRESSIONS, ELExpressionCacheMode.noCache.name());
+            
+            _elExpressionCacheMode = Enum.valueOf(ELExpressionCacheMode.class, value); 
+        }
+        return _elExpressionCacheMode;
+    }
+
+    @Override
     public void addAttachedObjectHandler(UIComponent compositeComponentParent, AttachedObjectHandler handler)
     {
         List<AttachedObjectHandler> list = _attachedObjectHandlers.get(compositeComponentParent);

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/PageContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/PageContextImpl.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/PageContextImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/PageContextImpl.java Thu Jun 16 18:01:26 2011
@@ -29,8 +29,11 @@ public class PageContextImpl extends Pag
     
     private Map<String, ValueExpression> _attributes = null;
     
+    private boolean _isCacheELExpressions;
+
     public PageContextImpl()
     {
+        _isCacheELExpressions = true;
     }
 
     @Override
@@ -48,4 +51,16 @@ public class PageContextImpl extends Pag
     {
         return _attributes == null ? 0 : _attributes.size();
     }
+
+    @Override
+    public boolean isAllowCacheELExpressions()
+    {
+        return _isCacheELExpressions;
+    }
+
+    @Override
+    public void setAllowCacheELExpressions(boolean cacheELExpressions)
+    {
+        _isCacheELExpressions = cacheELExpressions;
+    }
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/TemplateContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/TemplateContextImpl.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/TemplateContextImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/impl/TemplateContextImpl.java Thu Jun 16 18:01:26 2011
@@ -68,6 +68,8 @@ public class TemplateContextImpl extends
     private TemplateManager _compositeComponentClient;
     
     private TemplateManagerImpl _lastClient;
+    
+    private boolean _isCacheELExpressions;
 
     public TemplateContextImpl()
     {
@@ -81,6 +83,7 @@ public class TemplateContextImpl extends
         // to this manager. 
         _clients.add(new TemplateManagerImpl(null, INITIAL_TEMPLATE_CLIENT, true, INITIAL_PAGE_CONTEXT));
         _lastClient = _clients.getFirst();
+        _isCacheELExpressions = true;
     }
 
     @Override
@@ -369,6 +372,13 @@ public class TemplateContextImpl extends
     
     public static final class InitialPageContext extends PageContext
     {
+        private boolean _isCacheELExpressions;
+        
+        public InitialPageContext()
+        {
+            _isCacheELExpressions = true;
+        }
+        
         @Override
         public Map<String, ValueExpression> getAttributes()
         {
@@ -380,5 +390,32 @@ public class TemplateContextImpl extends
         {
             return 0;
         }
+
+        @Override
+        public boolean isAllowCacheELExpressions()
+        {
+            return _isCacheELExpressions;
+        }
+
+        @Override
+        public void setAllowCacheELExpressions(boolean cacheELExpressions)
+        {
+            _isCacheELExpressions = cacheELExpressions;
+        }
+    }
+
+
+    @Override
+    public boolean isAllowCacheELExpressions()
+    {
+        return _isCacheELExpressions;
     }
+
+    @Override
+    public void setAllowCacheELExpressions(boolean cacheELExpressions)
+    {
+        _isCacheELExpressions = cacheELExpressions;
+    }
+    
+    
 }

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=1136573&r1=1136572&r2=1136573&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 Thu Jun 16 18:01:26 2011
@@ -18,6 +18,8 @@
  */
 package org.apache.myfaces.view.facelets.tag;
 
+import java.util.Arrays;
+
 import javax.el.ELException;
 import javax.el.ExpressionFactory;
 import javax.el.MethodExpression;
@@ -28,6 +30,7 @@ import javax.faces.view.facelets.TagAttr
 import javax.faces.view.facelets.TagAttributeException;
 
 import org.apache.myfaces.util.ExternalSpecifications;
+import org.apache.myfaces.view.facelets.AbstractFaceletContext;
 import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
 import org.apache.myfaces.view.facelets.el.ELText;
 import org.apache.myfaces.view.facelets.el.LocationMethodExpression;
@@ -72,6 +75,14 @@ public final class TagAttributeImpl exte
 
     private String string;
 
+    /**
+     * This variable is used to cache created expressions using
+     * getValueExpression or getMethodExpression methods. It uses
+     * a racy single check strategy, because if the expression can be
+     * cached the same instance will be built.
+     */
+    private volatile Object[] cachedExpression;
+
     public TagAttributeImpl(Location location, String ns, String localName, String qName, String value)
     {
         boolean literal;
@@ -185,6 +196,26 @@ public final class TagAttributeImpl exte
      */
     public MethodExpression getMethodExpression(FaceletContext ctx, Class type, Class[] paramTypes)
     {
+        AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
+        
+        //volatile reads are atomic, so take the tuple to later comparison.
+        Object[] localCachedExpression = cachedExpression; 
+        
+        if (actx.isAllowCacheELExpressions() && localCachedExpression != null && (localCachedExpression.length % 3 == 0))
+        {
+            //If the expected type and paramTypes are the same return the cached one
+            for (int i = 0; i < (localCachedExpression.length/3); i++)
+            {
+                if ( ((type == null && localCachedExpression[(i*3)] == null ) ||
+                     (type != null && type.equals(localCachedExpression[(i*3)])) ) &&
+                     (Arrays.equals(paramTypes, (Class[]) localCachedExpression[(i*3)+1])) )
+                {
+                    return (MethodExpression) localCachedExpression[(i*3)+2];
+                }
+            }
+        }
+        
+        actx.beforeConstructELExpression();
         try
         {
             MethodExpression methodExpression = null;
@@ -229,12 +260,40 @@ public final class TagAttributeImpl exte
                 }
             }
             
-            return new TagMethodExpression(this, methodExpression);
+            methodExpression = new TagMethodExpression(this, methodExpression);
+                
+            if (actx.isAllowCacheELExpressions() && !actx.isAnyFaceletsVariableResolved())
+            {
+                if (localCachedExpression != null && (localCachedExpression.length % 3 == 0))
+                {
+                    // If you use a racy single check, assign
+                    // the volatile variable at the end.
+                    Object[] array = new Object[localCachedExpression.length+3];
+                    array[0] = type;
+                    array[1] = paramTypes;
+                    array[2] = methodExpression;
+                    for (int i = 0; i < localCachedExpression.length; i++)
+                    {
+                        array[i+3] = localCachedExpression[i];
+                    }
+                    cachedExpression = array;
+                }
+                else
+                {
+                    cachedExpression = new Object[]{type, paramTypes, methodExpression};
+                }
+            }
+
+            return methodExpression; 
         }
         catch (Exception e)
         {
             throw new TagAttributeException(this, e);
         }
+        finally
+        {
+            actx.afterConstructELExpression();
+        }
     }
     
     /**
@@ -360,6 +419,24 @@ public final class TagAttributeImpl exte
      */
     public ValueExpression getValueExpression(FaceletContext ctx, Class type)
     {
+        AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
+        
+        //volatile reads are atomic, so take the tuple to later comparison.
+        Object[] localCachedExpression = cachedExpression;
+        if (actx.isAllowCacheELExpressions() && localCachedExpression != null && localCachedExpression.length == 2)
+        {
+            //If the expected type is the same return the cached one
+            if (localCachedExpression[0] == null && type == null)
+            {
+                return (ValueExpression) localCachedExpression[1];
+            }
+            else if (localCachedExpression[0] != null && localCachedExpression[0].equals(type))
+            {
+                return (ValueExpression) localCachedExpression[1];
+            }
+        }
+
+        actx.beforeConstructELExpression();
         try
         {
             ExpressionFactory f = ctx.getExpressionFactory();
@@ -402,12 +479,21 @@ public final class TagAttributeImpl exte
                 }
             }
             
+            
+            if (actx.isAllowCacheELExpressions() && !actx.isAnyFaceletsVariableResolved())
+            {
+                cachedExpression = new Object[]{type, valueExpression};
+            }
             return valueExpression;
         }
         catch (Exception e)
         {
             throw new TagAttributeException(this, e);
         }
+        finally
+        {
+            actx.afterConstructELExpression();
+        }
     }
 
     /**

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/UserTagHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/UserTagHandler.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/UserTagHandler.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/UserTagHandler.java Thu Jun 16 18:01:26 2011
@@ -112,18 +112,28 @@ final class UserTagHandler extends TagHa
         // eval include
         try
         {
-            String[] names = new String[_vars.length];
-            ValueExpression[] values = new ValueExpression[_vars.length];
-            for (int i = 0; i < _vars.length; i++)
-            {
-                names[i] = _vars[i].getLocalName();
-                values[i] = _vars[i].getValueExpression(ctx, Object.class);
+            String[] names = null;
+            ValueExpression[] values = null;
+            if (this._vars.length > 0)
+            {
+                names = new String[_vars.length];
+                values = new ValueExpression[_vars.length];
+                for (int i = 0; i < _vars.length; i++)
+                {
+                    names[i] = _vars[i].getLocalName();
+                    values[i] = _vars[i].getValueExpression(ctx, Object.class);
+                }
             }
             actx.pushTemplateContext(new TemplateContextImpl());
-            for (int i = 0; i < this._vars.length; i++)
+            if (this._vars.length > 0)
             {
-                ((AbstractFaceletContext) ctx).getTemplateContext().setParameter(names[i], values[i]);
+                for (int i = 0; i < this._vars.length; i++)
+                {
+                    ((AbstractFaceletContext) ctx).getTemplateContext().setParameter(names[i], values[i]);
+                }
             }
+            //Disable caching always, even in 'always' mode
+            actx.getTemplateContext().setAllowCacheELExpressions(false);
             actx.pushClient(this);
             ctx.includeFacelet(parent, this._location);
         }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/SetHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/SetHandler.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/SetHandler.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jstl/core/SetHandler.java Thu Jun 16 18:01:26 2011
@@ -35,6 +35,7 @@ import javax.faces.view.facelets.TagHand
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
+import org.apache.myfaces.view.facelets.ELExpressionCacheMode;
 
 /**
  * Simplified implementation of c:set
@@ -132,7 +133,15 @@ public class SetHandler extends TagHandl
                 expr.setValue(elCtx, veObj.getValue(elCtx));
             } else {
                 //ctx.getVariableMapper().setVariable(varStr, veObj);
-                ((AbstractFaceletContext) ctx).getPageContext().getAttributes().put(varStr, veObj);
+                AbstractFaceletContext actx = ((AbstractFaceletContext) ctx);
+                actx.getPageContext().getAttributes().put(varStr, veObj);
+                if (actx.getPageContext().isAllowCacheELExpressions())
+                {
+                    if (ELExpressionCacheMode.strict.equals(actx.getELExpressionCacheMode()))
+                    {
+                        actx.getPageContext().setAllowCacheELExpressions(false);
+                    }
+                }
             }
         }
         else

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/ui/ParamHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/ui/ParamHandler.java?rev=1136573&r1=1136572&r2=1136573&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/ui/ParamHandler.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/ui/ParamHandler.java Thu Jun 16 18:01:26 2011
@@ -33,6 +33,7 @@ import javax.faces.view.facelets.TagHand
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
+import org.apache.myfaces.view.facelets.ELExpressionCacheMode;
 
 /**
  * @author Jacob Hookom
@@ -88,7 +89,17 @@ public class ParamHandler extends TagHan
             ELException
     {
         //((AbstractFaceletContext) ctx).getTemplateContext().getAttributes().put(nameStr, valueVE);
-        ((AbstractFaceletContext) ctx).getTemplateContext().setParameter(nameStr, valueVE);
+        AbstractFaceletContext actx = ((AbstractFaceletContext) ctx); 
+        actx.getTemplateContext().setParameter(nameStr, valueVE);
+        
+        if (actx.getTemplateContext().isAllowCacheELExpressions())
+        {
+            if (ELExpressionCacheMode.strict.equals(actx.getELExpressionCacheMode()) ||
+                ELExpressionCacheMode.allowCset.equals(actx.getELExpressionCacheMode()))
+            {
+                actx.getTemplateContext().setAllowCacheELExpressions(false);
+            }
+        }
     }
     
     public String getName(FaceletContext ctx)