[
https://issues.apache.org/jira/browse/TRINIDAD-1238?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12637217#action_12637217
]
Andrew Robinson commented on TRINIDAD-1238:
-------------------------------------------
Adding some more detail on this:
There are multiple facets to this problem. The underlying problem is that
partialTriggers is not context safe. What I mean by this is that the code
actually violates the JSF way of doing things. Here is how PPR works:
1) During decode of a component UIXComponentBase sets up a map of PPR
listeners. When it does this, it uses UIComponent references, not client IDs
2) When an event is broadcast, the listeners are added as partial targets. As
the components are added, their client IDs are retrieved and added to a list of
client DOM elements that should be replaced on the client.
Inside of org.apache.myfaces.trinidadinternal.context.RequestContextImpl, two
pieces of data are maintained:
1) A Map<UIComponent, Set<UIComponent>> that contains a set of listeners for
every component
2) A Set<String> that contains the list of client IDs that are to be replaced
on the client.
Now when the listeners are processed (like when a commandLink's ActionEvent is
broadcast), its listeners are added. The problem is that the components are now
out of scope.
In the case of an iterator, the child is added to the Map<UIComponent,
Set<UIComponent>>. At this time, the stamp of the component is known and the
component is "in scope" (for example, the table var attribute is in scope and
can be evaluated). When a link outside the iterator has its event broadcast,
that iterator child is out of scope (its variables and its client ID are no
longer available).
The best fix that comes to me is to change the innards of RequestContextImpl as
such:
1) Change Map<UIComponent, Set<UIComponent>> to Map<UIComponent, Set<String>>.
The String would be the client ID of the component to target.
2) On addPartialTrigger, loop through these strings, use invokeOnComponent on
that client ID, and then use that component, in scope, and add it to the list.
This method would (1) make sure that the correct client IDs are added to the
response and (2) would make sure that any EL expressions that are evaluated on
the component are in the correct scope.
Now, using invokeOnComponent is not fast. invokeOnComponent must always be
executed on the view root. Therefore, deep components would create a larger
overhead on the PPR mechanism, which is definitely not desired.
The other alternative is to remove the method "private UIComponent
_getNearestPPRTarget(UIComponent component)" that is called from the
"addPartialTarget(UIComponent newTarget)" method. This is the only method that
requires that a UIComponent is present, as opposed to a client ID. The body of
this method is:
private UIComponent _getNearestPPRTarget(UIComponent component)
{
while(component.getRendererType() == null)
{
component = component.getParent();
}
return component;
}
Which is actually flawed. I can have a component without a renderer type that
encodes HTML. Now it is not a recommended practice, but it is valid.
So as a 2nd solution that would have better performance is this:
1) Change Map<UIComponent, Set<UIComponent>> to Map<UIComponent, Set<String>>.
The String would be the client ID of the component to target.
2) In "private void _addTargets(Object key)", just add the client IDs to the
list of IDs, instead of looping through the components or using
invokeOnComponent
The disadvantage to any of this is that the "public Set<UIComponent>
getPartialTargets(UIComponent source)" API method on RequestContext depends on
the current Map.
When I said that this issue should be discussed on the dev@ mailing list, it is
because of:
1) If invokeOnComponent were to be used, is this feature important enough to
incur that overhead?
2) If we store Strings instead of UIComponent references, what would be the
performance impact on "public Set<UIComponent> getPartialTargets(UIComponent
source)"?
So I do not think that this may not have value, but whether or not the effort
and the risk to implement this feature is worth the benefit that would be
achieved.
Another thought on this discussion would be to add a "partialTargets" attribute
onto UIXComponentBase that would result in better performance than
"partialTriggers" since a list of listeners would not need to be kept. Partial
targets functionality would also improve the use case where many command
objects update one component. Instead of adding 10s of partialTriggers on the
one component, each command button would point to the one component to update
instead. This would not replace partialTriggers, but it could lessen the
performance impact of the partialTriggers implementation.
> Allow children of iterator to use partialTriggers
> -------------------------------------------------
>
> Key: TRINIDAD-1238
> URL: https://issues.apache.org/jira/browse/TRINIDAD-1238
> Project: MyFaces Trinidad
> Issue Type: New Feature
> Components: Components
> Affects Versions: 1.0.9-core, 1.2.9-core
> Reporter: Matt Cooper
> Attachments: test.jspx, testCase.diff
>
>
> Today, if you have an iterator that stamps out components, these components
> cannot have partialTriggers where, for example, a specified button would not
> cause the component to be PPRed when clicked.
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.