You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@myfaces.apache.org by "Leonardo Uribe (JIRA)" <de...@myfaces.apache.org> on 2013/11/23 19:11:35 UTC

[jira] [Resolved] (MYFACES-3825) [perf] Cache EL expressions using an indirection for ui:param and user tag attributes

     [ https://issues.apache.org/jira/browse/MYFACES-3825?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Leonardo Uribe resolved MYFACES-3825.
-------------------------------------

       Resolution: Fixed
    Fix Version/s: 2.2.0

> [perf] Cache EL expressions using an indirection for ui:param and user tag attributes
> -------------------------------------------------------------------------------------
>
>                 Key: MYFACES-3825
>                 URL: https://issues.apache.org/jira/browse/MYFACES-3825
>             Project: MyFaces Core
>          Issue Type: Improvement
>          Components: JSR-344
>            Reporter: Leonardo Uribe
>            Assignee: Leonardo Uribe
>             Fix For: 2.2.0
>
>
> I have been trying for some time to find new ways to improve the code inside
> MyFaces. Working in MYFACES-3811 (fix c:forEach) I have realized that the way
> how VariableMapper works allows us to cache EL expressions in those places where
> we have thought EL caching was not possible. 
> This fact is important because it changes the way how we have been thinking around
> view pooling technique (See MYFACES-3664 for details). If all 
> ValueExpression/MethodExpression instances in a view can be considered "static" or
> in other words it does not change each time the view is built or refreshed, we can
> be sure that with a plain visitTree call it is possible to "reset" any view and
> reuse it safely, even in cases like when ui:param is used or user facelet tags.
> If all components in a view support pooling (hard/soft reset using saveState 
> method), any view using those components can be poolable. 
> First of all, let's remember how VariableMapper works. Basically it is just a map
> with var names as keys and ValueExpression as values. When a EL expression is
> created, the variables that are on the context VariableMapper and are used
> to solve the expression are copied and stored into an inner VariableMapper of
> the created EL expression. For example if we have this:
> <c:set var="item" value="Hello"/>
> <c:set var="item2" value="#{item}"/>
> <c:set var="item3" value="#{item2}"/>
> the EL expression for item2 will have an inner VariableMapper with an EL
> expression pointing to "Hello".
> Now, we need to remember the problematic cases for EL caching:
> 1. Use combinations of c:set and c:if
>     <c:if test="#{condition}">
>         <c:set var="item" value="Hello"/>
>     <c:if>
>     <h:outputText value="#{item}"/>
> This case is unlikely, but most of all, it can be refactored very easily to avoid
> the c:if and move the condition to the c:set EL Expression. It is common to found
> this technique in old JSP pages. But it is clear with JSF, this kind of logic
> should reside in a managed bean. So at the end it is not a big deal. Anyway, 
> There is a mode called "strict" that disable EL caching for the whole page if 
> c:set is found.
> 2. Use of ui:param
>     <ui:decorate template="uiparamcache1_1.xhtml">
>     </ui:decorate>
>     <ui:decorate template="uiparamcache1_1.xhtml">
>         <ui:param name="param1" value="ALFA"/>
>     </ui:decorate>
> The first time the template is called, it has no params, so all expressions are
> cached inside the inner template. But once we call the same template again, those
> cached expressions are now invalid and needs to be recalculated again. The hack
> done with "alwaysRecompile" mode recompiles the facelet, but takes into account
> the known parameters for the template. In this way, the EL expressions that are
> affected by the param are not cached.
> 3. Use of facelet user tags
>     <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>
>     
> This is quite the same to the case with ui:param, but in this case affect facelet tag 
> attributes. 
> 4. An expression uses a variable resolved through VariableMapper
> This is unlikely, because there are no standard tags using this strategy, but it is
> possible to create a facelet tag that uses a VariableMapper wrapper. This is not 
> something we should worry about.
> In MYFACES-3811 (fix c:forEach), there is a part where a wrapper 
> (IteratedValueExpression or MappedValueExpression) is required to hold 
> the associated item and inject it into the VariableMapper. This is indeed a good idea,
> because it shows that we can just put a wrapper inside VariableMapper and things will
> keep working. 
> If we can substitute the ValueExpression associated with a var with something else, we
> can avoid the propagation effect that makes EL caching fail in 2 and 3. The trick is 
> use an unique id associated with the facelet tag and put the real EL expression in
> a central point like FaceletState object, which is stored in UIViewRoot. The resulting
> structure can be generated over and over if PSS is enabled and if is disable, it needs
> to be saved with the state. If the component tree changes dynamically, the generated
> structure will change too.
> The final effect will be that 100% of the EL Expressions managed by facelets using 
> "alwaysRecompile" mode will be cacheable, which will be a great improvement. It also
> removes one of the biggest disadvantages we had for include view pooling technique
> into MyFaces 2.2.x.



--
This message was sent by Atlassian JIRA
(v6.1#6144)