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

Leonardo Uribe resolved MYFACES-3711.
-------------------------------------

       Resolution: Fixed
    Fix Version/s: 2.1.12
    
> Add alwaysRecompile mode for EL Expression Cache Mode
> -----------------------------------------------------
>
>                 Key: MYFACES-3711
>                 URL: https://issues.apache.org/jira/browse/MYFACES-3711
>             Project: MyFaces Core
>          Issue Type: New Feature
>          Components: JSR-314
>            Reporter: Leonardo Uribe
>            Assignee: Leonardo Uribe
>             Fix For: 2.1.12
>
>         Attachments: MYFACES-3711-1-alwaysRecompile.patch
>
>
> In MYFACES-3160, EL Expression Cache Mode was introduced but soon it was seen 
> a
> problem found on MYFACES-3169 (ui:param and c:set implementations does not 
> work as expected).
> There are two problems that limit the scope where EL Expression Cache can 
> be used:
> 1. Facelets user tags cannot cache EL Expressions.
> 2. Inclusions using ui:param must always contains the same number of 
> parameters.
> To understand the reasons it is worth to remember this example:
> a.xhtml
> <ui:composition template="c.xhtml">
>     <ui:param name="var1" value="value1"/>
> </ui:composition>
> b.xhtml
> <ui:composition template="c.xhtml">
>     <ui:param name="var1" value="value1"/>
>     <ui:param name="var2" value="value2"/>
> </ui:composition>
> c.xhtml
> <ui:composition>
>    <h:outputText value="#{var1}/>
>    <h:outputText value="#{var2}/>
> </ui:composition>
> When facelet c.xhtml is constructed from a.xhtml, "var2" is not recognized as
> a parameter so all EL expressions inside c.xhtml holding refereces to "var2"
> will be cached. Later, facelet c.xhtml is reused from b.xhtml but since 
> some EL expressions are cached the passed value in "var2" is not taken into 
> account and the error arise.
> In this point it is good to remember that ui:include or ui:decorate or user 
> tags are build view time tags, so they are executed only when the view is
> built. Parameters or attributes passed by ui:param or as user tag attributes
> follows the same principle, they are calculated on build view time through
> VariableMapper and the evaluation is stored inside the EL Expression. This
> means all EL Expressions holding references to these variables cannot be
> cached and needs to be generated each time the view is built.
> There is no way to know beforehand which references are affected, because
> in a template or an user tag there is no declaration of the parameters or
> attributes. But from user point of view that's good, because in this context
> a declaration of the parameters is just not necessary.
> The problem is ui:param and user tags are very useful features, widely used.
> A solution to this problem will improve performance in those cases.
> I have been thinking for a long time how to solve this, trying different 
> strategies. Use some kind of concurrency algorithm inside TagAttributeImpl
> does not work because it is too expensive, or use a central storage for 
> cache the expressions by the cost involved in the comparisons.
> The objective of cache EL expressions inside facelets abstract syntax tree 
> (AST) is minimize the calculations required to get a valid expression. EL
> implementations has already an internal map that cache that information,
> but that code usually has synchronized blocks or similar things. In that
> sense, the idea is rely on that storage in those EL expressions where 
> there is no choice and they need to be recreated.
> After doing many experiments in this part, I came up with a solution, which
> involves the following points:
> 1. Associate to a facelet, the parameters that were considered as passed 
> through ui:param or as a user tag attribute. If in some point of time
> we know for example c.xhtml uses var1, just consider it as c.xhtml(var1).
> 2. Use DefaultVariableMapper to track the parameters that are passed through
> ui:param or as a user tag attribute. When the EL expression is created, if
> it uses at least one parameter, mark the expression as not cacheable.
> 3. Override FaceletCache implementation and force a recompilation of a 
> facelet if a new parameter is detected that was not considered the first 
> time the template was created.
> 4. A facelet stored in the cache can be used if and only if all the 
> parameters used for the template where considered when it was compiled at
> first time.
> In the example proposed, when facelet c.xhtml is constructed from a.xhtml,
> we say that c.xhtml was built with var1 as a known parameter, or 
> c.xhtml(var1). when we try to reuse facelet c.xhtml from b.xhtml, we discover
> that var2 is also a parameter, but since the cached facelet is c.xhtml(var1),
> the algorithm discard the facelet and create a new one, but taking into
> account var2 too, so the new facelet becomes c.xhtml(var1,var2). If there
> is a call to c.xhtml with no params, it is considered that c.xhtml(var1,var2)
> can be used in that case.
> The final effect is just some extra compilations of the same facelet at
> startup but in the medium/long term, the information we need is calculated 
> and associated with the facelet url. Nice!. Facelet is very fast doing those
> extra compilation steps, and the final effect over performance really pays 
> off. We could even set this mode as default.
> The only disadvantage of this strategy is the current contract of FaceletCache
> is insuficient. As it has been described in MYFACES-3705, there are 
> implementation details inside MyFaces Core and in our facelets implementation,
> that needs to be exposed in a proper way. We need to create a custom
> AbstractFaceletCache and specify how to implement it.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to