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

Reply via email to