[ 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