Duplicate id exception for HtmlDataScrollerRenderer

Details

Description

In a portlet environment a non-faces request produces an exception when the faces tree is rendered if the faces tree contains a DataScroller component. The HtmlDataScroller renderer actually renders its children twice in this case, once in the encodeChildren method and once in the encodeEnd method. Since rendering of the children is taken care of in encodeEnd I made the encodeChildren method a no-op. Also, although the CommandLinks which are rendered as children are marked as transient, they see to stick around. I put a check in the getLink methods to make sure that the links are not added twice. This seems to fix the duplicate id exception, but it might be necessary to further investigate why they are sticking around in the first place.

Activity

I don't see where it's rendering its children in encodeEnd. I'm not an expert on renderers, though.

Also, if you could provide a full path in your patches in the future, it'd make applying them easier.
It's not always obvious where xyz.java is located.

It would also be useful if your patch compiled. Since it doesn't, I'm a bit concerned about applying it
It's missing typecasts from UIComponent to UICommandLink, and this makes me think I'm applying untested code.

Mike Kienenberger
added a comment - 16/Aug/06 02:48 I don't see where it's rendering its children in encodeEnd. I'm not an expert on renderers, though.
Also, if you could provide a full path in your patches in the future, it'd make applying them easier.
It's not always obvious where xyz.java is located.
It would also be useful if your patch compiled. Since it doesn't, I'm a bit concerned about applying it
It's missing typecasts from UIComponent to UICommandLink, and this makes me think I'm applying untested code.
-Mike

Sorry for my sloppiness, Mike. I tested this patch on a different machine which was setup with Portal Server on it. Then I created the patch by hand on a different machine and missed the typecast. I realize this is not a good practice at all.

The children are being rendered in encodeEnd through the call to renderFacet...

I will only submit from my development machine from now on. By the way to replicate this problem use the datascroller inside a portlet. Then click on a link inside another portlet on the same page or any link on the same page which is not part of the datascroller portlet.

Ryan Wynn
added a comment - 17/Aug/06 04:09 Sorry for my sloppiness, Mike. I tested this patch on a different machine which was setup with Portal Server on it. Then I created the patch by hand on a different machine and missed the typecast. I realize this is not a good practice at all.
The children are being rendered in encodeEnd through the call to renderFacet...
protected void renderFacet(FacesContext facesContext, HtmlDataScroller scroller,
UIComponent facetComp, String facetName) throws IOException
{
UIComponent link = getLink(facesContext, scroller, facetName);
link.encodeBegin(facesContext);
facetComp.encodeBegin(facesContext);
if (facetComp.getRendersChildren())
facetComp.encodeChildren(facesContext);
facetComp.encodeEnd(facesContext);
link.encodeEnd(facesContext);
}
I will only submit from my development machine from now on. By the way to replicate this problem use the datascroller inside a portlet. Then click on a link inside another portlet on the same page or any link on the same page which is not part of the datascroller portlet.

I hear what you are saying about the facet and non-fact children. But that is not the behavior I am experiencing. What happens if I do not comment out the lines in the encodeChildren method is that I get 2 rows of paging links instead of 1. Like this...

12345678910
1 2 3 4 5 6 7 8 9 10

underneath my table. And for some reason the first row is rendered as one anchor with 123456 (all the pages)... inside it. While the second row behaves properly with each page having it own anchor.

It's really weird but the patch seems to fix it. It only happens when you force a nonFacesRequest in a portlet environment by clicking anywhere outside of your portlet.

Ryan Wynn
added a comment - 17/Aug/06 18:00 I hear what you are saying about the facet and non-fact children. But that is not the behavior I am experiencing. What happens if I do not comment out the lines in the encodeChildren method is that I get 2 rows of paging links instead of 1. Like this...
12345678910
1 2 3 4 5 6 7 8 9 10
underneath my table. And for some reason the first row is rendered as one anchor with 123456 (all the pages)... inside it. While the second row behaves properly with each page having it own anchor.
It's really weird but the patch seems to fix it. It only happens when you force a nonFacesRequest in a portlet environment by clicking anywhere outside of your portlet.

Mike Kienenberger
added a comment - 17/Aug/06 18:04 If you use your patch in a non-portlet environment, what happens?
Between the two of us, you're the portlet expert, so if you say it works better in portlets with it commented out, I believe you But we also have to support all of the non-portlet users too

Here's my fix. As I do not have commit right and don't want to re-create a patch for every MyFaces update, I have simple derived a working renderer.

Effectively, I have commented out encodeChildren as well, but I simply remove the "left over" command links before rendering the scroller. See my comments in TOMAHAWK-657.

As for checking this in a non-portlet environment, I'm afraid I won't be able to help here as my application is portal based and I don't have another non-portle based JSF application with data scrollers. But I'm sure the MyFaces team has some test case for data scroller, don't you?

Michael Lipp
added a comment - 06/Sep/06 08:18 Here's my fix. As I do not have commit right and don't want to re-create a patch for every MyFaces update, I have simple derived a working renderer.
Effectively, I have commented out encodeChildren as well, but I simply remove the "left over" command links before rendering the scroller. See my comments in TOMAHAWK-657 .
As for checking this in a non-portlet environment, I'm afraid I won't be able to help here as my application is portal based and I don't have another non-portle based JSF application with data scrollers. But I'm sure the MyFaces team has some test case for data scroller, don't you?

I have also a problem with the datascroller and duplicated ids in combination with ajax4jsf. This is in a non-portlet environment.
HtmlDataScrollerRenderer re-creates commandLinks on every rendering in the getLink methods.
The applied patch does not work!

The children of the datascroller are not processed anymore with the above patch.
e.g. the summary of a scroller is not displayed anymore.
<t:dataScroller id="scroller" ...>
<h:outputFormat value="aSummary">
<f:param value="#

{rowsCount}

" />
<f:param value="#

{lastRowIndex}

" />
</t:dataScroller>

If I manipulate the datamodel in the backend and remove some entries then I still got links for pages which are not existing anymore.
This means that existing links have to be dropped.

Michael Heinen
added a comment - 24/Oct/06 17:54 I have also a problem with the datascroller and duplicated ids in combination with ajax4jsf. This is in a non-portlet environment.
HtmlDataScrollerRenderer re-creates commandLinks on every rendering in the getLink methods.
The applied patch does not work!
The children of the datascroller are not processed anymore with the above patch.
e.g. the summary of a scroller is not displayed anymore.
<t:dataScroller id="scroller" ...>
<h:outputFormat value="aSummary">
<f:param value="#
{rowsCount}
" />
<f:param value="#
{lastRowIndex}
" />
</t:dataScroller>
If I manipulate the datamodel in the backend and remove some entries then I still got links for pages which are not existing anymore.
This means that existing links have to be dropped.

If the underlying datamodel is updated via ajax and the number of the displayed pager links is increased (e,.g a display filter removed), then these links are not precessed correctly. I think you need static ids build from 1 til paginatorMaxPages and even dummyLinks if your model contains less pages or if the scroller is even not rendered because the model contains only a single page.

What about the children ?
Is the summary still encoded or is it skipped due to the empty encodeChildren method?
I did not find a solution for this except splitting the datascroller into two tags with separate renderes.

Michael Heinen
added a comment - 22/Nov/06 15:27 This patch works also only in a subset of the usecases.
Pls see http://issues.apache.org/jira/browse/TOMAHAWK-768
If the underlying datamodel is updated via ajax and the number of the displayed pager links is increased (e,.g a display filter removed), then these links are not precessed correctly. I think you need static ids build from 1 til paginatorMaxPages and even dummyLinks if your model contains less pages or if the scroller is even not rendered because the model contains only a single page.
What about the children ?
Is the summary still encoded or is it skipped due to the empty encodeChildren method?
I did not find a solution for this except splitting the datascroller into two tags with separate renderes.
Michael

I'm also seeing this problem with a portlet I'm developing with JSF using the Tomahawk t:dataTable action in combination with t:dataScroller for implementing a pageable search results page.
The page includes a form for typing in search criteria and dataTable is used for representing the results.
Part of the time this is working as expected but occasionally I receive error messages about duplicate components in the component tree (see below).
I'm using Tomahawk 1.1.3 and the application runs on WebSphere Portal Server 6.0.
I've also tested this with Tomahawk 1.1.6 and the issue can be reproduced with that version as well.

at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.saveSerializedView(JspStateManagerImpl.java:305)
at org.apache.myfaces.taglib.core.ViewTag.doAfterBody(ViewTag.java:122)
at com.ibm._jsp._listReports._jspx_meth_f_view_0(_listReports.java:1671)
at com.ibm._jsp._listReports._jspService(_listReports.java:89)
at com.ibm.ws.jsp.runtime.HttpJspBase.service(HttpJspBase.java(Compiled Code))
at javax.servlet.http.HttpServlet.service(HttpServlet.java(Compiled Code))
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java(Compiled Code))
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java(Compiled Code))
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java(Compiled Code))
at com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java(Compiled Code))
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java(Compiled Code))
at com.ibm.wsspi.webcontainer.servlet.GenericServletWrapper.handleRequest(GenericServletWrapper.java(Inlined Compiled Code))
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.handleRequest(JSPExtensionServletWrapper.java(Compiled Code))
at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.include(WebAppRequestDispatcher.java(Compiled Code))
at org.apache.pluto.core.impl.PortletRequestDispatcherImpl.include(PortletRequestDispatcherImpl.java:112)
... 170 more

Marko Asplund
added a comment - 17/Jan/08 09:12 I'm also seeing this problem with a portlet I'm developing with JSF using the Tomahawk t:dataTable action in combination with t:dataScroller for implementing a pageable search results page.
The page includes a form for typing in search criteria and dataTable is used for representing the results.
Part of the time this is working as expected but occasionally I receive error messages about duplicate components in the component tree (see below).
I'm using Tomahawk 1.1.3 and the application runs on WebSphere Portal Server 6.0.
I've also tested this with Tomahawk 1.1.6 and the issue can be reproduced with that version as well.
Caused by: java.lang.IllegalStateException: Client-id : scrollerprevious is duplicated in the faces tree. Component : listForm:scrollerprevious, path:
{Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /WEB-INF/jsp/acars/listReports.jsp][Class: org.apache.myfaces.custom.div.Div,Id: _idJsp0PC_7_BAQQI5230OL3C02
T1C1LCM30D2_][Class: javax.faces.component.html.HtmlForm,Id: listForm][Class: org.apache.myfaces.custom.div.Div,Id: _idJsp38PC_7_BAQQI5230OL3C02T1C1LCM30D2_][Class: javax.faces.component.html.HtmlPanelGrid,Id: _idJsp80PC_7_BAQQI5230OL3C02T1C1LCM30D2_][Class: org.apache.myfaces.custom.datascroller.HtmlDataScroller,Id: scroller][Class: javax.faces.component.html.HtmlCommandLink,Id: scrollerprevious]}
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.checkForDuplicateIds(JspStateManagerImpl.java(Compiled Code))
at org.apache.myfaces.application.jsp.JspStateManagerImpl.saveSerializedView(JspStateManagerImpl.java:305)
at org.apache.myfaces.taglib.core.ViewTag.doAfterBody(ViewTag.java:122)
at com.ibm._jsp._listReports._jspx_meth_f_view_0(_listReports.java:1671)
at com.ibm._jsp._listReports._jspService(_listReports.java:89)
at com.ibm.ws.jsp.runtime.HttpJspBase.service(HttpJspBase.java(Compiled Code))
at javax.servlet.http.HttpServlet.service(HttpServlet.java(Compiled Code))
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java(Compiled Code))
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java(Compiled Code))
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java(Compiled Code))
at com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java(Compiled Code))
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java(Compiled Code))
at com.ibm.wsspi.webcontainer.servlet.GenericServletWrapper.handleRequest(GenericServletWrapper.java(Inlined Compiled Code))
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.handleRequest(JSPExtensionServletWrapper.java(Compiled Code))
at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.include(WebAppRequestDispatcher.java(Compiled Code))
at org.apache.pluto.core.impl.PortletRequestDispatcherImpl.include(PortletRequestDispatcherImpl.java:112)
... 170 more

Attached is a fix that sorted out this issue in portlet environment. The fix prevents repeated addition of HTML link component to the data scroller that was a cause of having duplicate element inside the data scroller component.

The DIFF file was generated against version 1.1.8

The difference with the original patch issued by Ryan Wynn is that it doesn't comment out the the encodeChildren method although i think there is an ample reason for it as the data scroller is not supposed to have any children and UICommand components that wrap everything inside facets are not component children

Milan Majercik
added a comment - 02/Mar/09 17:32 - edited Attached is a fix that sorted out this issue in portlet environment. The fix prevents repeated addition of HTML link component to the data scroller that was a cause of having duplicate element inside the data scroller component.
The DIFF file was generated against version 1.1.8
The difference with the original patch issued by Ryan Wynn is that it doesn't comment out the the encodeChildren method although i think there is an ample reason for it as the data scroller is not supposed to have any children and UICommand components that wrap everything inside facets are not component children

The patch proposed by Milan Majercik has sense and does not cause the side effects of other patches like the one proposed on TOMAHAWK-1249.

I review it and did the necessary fixes, like remove links generated by paginator section and correct the section related to generated facet links (needed to solve TOMAHAWK-1249). Thanks to Milan Majercik for this patch.

Leonardo Uribe
added a comment - 10/Jun/09 02:14 The patch proposed by Milan Majercik has sense and does not cause the side effects of other patches like the one proposed on TOMAHAWK-1249 .
I review it and did the necessary fixes, like remove links generated by paginator section and correct the section related to generated facet links (needed to solve TOMAHAWK-1249 ). Thanks to Milan Majercik for this patch.