[
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)