MyFaces Tomahawk
  1. MyFaces Tomahawk
  2. TOMAHAWK-596

Duplicate id exception for HtmlDataScrollerRenderer

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.1.3
    • Fix Version/s: 1.1.9
    • Component/s: Data Scroller
    • Labels:
      None
    • Environment:
      Linux, Windows

      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.

      1. ASF.LICENSE.NOT.GRANTED--HtmlDataScrollerRenderer.patch
        4 kB
        Ryan Wynn
      2. HtmlDataScrollerRenderer.java
        2 kB
        Michael Lipp
      3. HtmlDataScrollerRenderer.java.example
        16 kB
        Maximiliano Carrizo
      4. datascroller-issue.txt
        209 kB
        Marko Asplund
      5. HtmlDataScrollerRenderer.patch
        4 kB
        Milan Majercik
      6. TOMAHAWK-596.patch
        9 kB
        Leonardo Uribe

        Issue Links

          Activity

          Hide
          Mike Kienenberger added a comment -

          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

          Show
          Mike Kienenberger added a comment - 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
          Hide
          Ryan Wynn added a comment -

          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.

          Show
          Ryan Wynn added a comment - 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.
          Hide
          Mike Kienenberger added a comment -

          This only renders the children of a facet.
          It doesn't render the non-facet children of datascroller.

          I haven't tested it (since I haven't installed your patch), but I'd guess it'd break this kind of DataScroller usage:

          <t:dataScroller id="scroll_information"
          for="searchResultsDataTable"
          rowsCountVar="rowsCount"
          displayedRowsCountVar="displayedRowsCountVar"
          firstRowIndexVar="firstRowIndex"
          lastRowIndexVar="lastRowIndex"
          pageCountVar="pageCount"
          pageIndexVar="pageIndex"
          >
          <h:panelGrid
          columns="1">
          <h:outputFormat value="

          {0}

          records found, displaying

          {1}

          records, from

          {2}

          to

          {3}

          . Page

          {4}

          /

          {5}

          " styleClass="standard" >
          <f:param value="#

          {rowsCount}

          " />
          <f:param value="#

          {displayedRowsCountVar}

          " />
          <f:param value="#

          {firstRowIndex}

          " />
          <f:param value="#

          {lastRowIndex}

          " />
          <f:param value="#

          {pageIndex}

          " />
          <f:param value="#

          {pageCount}

          " />
          </h:outputFormat>
          </h:panelGrid>
          </t:dataScroller>

          Also, I don't have access to a portlet environment to test this. Sorry about that, but I can only master so many technologies at once

          Show
          Mike Kienenberger added a comment - This only renders the children of a facet. It doesn't render the non-facet children of datascroller. I haven't tested it (since I haven't installed your patch), but I'd guess it'd break this kind of DataScroller usage: <t:dataScroller id="scroll_information" for="searchResultsDataTable" rowsCountVar="rowsCount" displayedRowsCountVar="displayedRowsCountVar" firstRowIndexVar="firstRowIndex" lastRowIndexVar="lastRowIndex" pageCountVar="pageCount" pageIndexVar="pageIndex" > <h:panelGrid columns="1"> <h:outputFormat value=" {0} records found, displaying {1} records, from {2} to {3} . Page {4} / {5} " styleClass="standard" > <f:param value="# {rowsCount} " /> <f:param value="# {displayedRowsCountVar} " /> <f:param value="# {firstRowIndex} " /> <f:param value="# {lastRowIndex} " /> <f:param value="# {pageIndex} " /> <f:param value="# {pageCount} " /> </h:outputFormat> </h:panelGrid> </t:dataScroller> Also, I don't have access to a portlet environment to test this. Sorry about that, but I can only master so many technologies at once
          Hide
          Ryan Wynn added a comment -

          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.

          Show
          Ryan Wynn added a comment - 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.
          Hide
          Mike Kienenberger added a comment -

          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

          Show
          Mike Kienenberger added a comment - 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
          Hide
          Michael Lipp added a comment -

          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?

          Show
          Michael Lipp added a comment - 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?
          Hide
          Michael Heinen added a comment -

          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.

          Show
          Michael Heinen added a comment - 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.
          Hide
          Maximiliano Carrizo added a comment -

          Here is an example of HtmlDataScrollerRenderer working with Ajax4jsf. Bye

          Show
          Maximiliano Carrizo added a comment - Here is an example of HtmlDataScrollerRenderer working with Ajax4jsf. Bye
          Hide
          Michael Heinen added a comment -

          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

          Show
          Michael Heinen added a comment - 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
          Hide
          Marko Asplund added a comment -

          Is any work being done to fix this problem?

          What's the recommended workaround?

          Show
          Marko Asplund added a comment - Is any work being done to fix this problem? What's the recommended workaround?
          Hide
          Marko Asplund added a comment -

          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

          Show
          Marko Asplund added a comment - 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
          Hide
          Marko Asplund added a comment -

          More complete log extract for the "scrollerprevious is duplicated in the faces tree" issue.

          Show
          Marko Asplund added a comment - More complete log extract for the "scrollerprevious is duplicated in the faces tree" issue.
          Hide
          Milan Majercik added a comment - - 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

          Show
          Milan Majercik added a comment - - 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
          Hide
          Leonardo Uribe added a comment -

          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.

          Show
          Leonardo Uribe added a comment - 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.

            People

            • Assignee:
              Leonardo Uribe
              Reporter:
              Ryan Wynn
            • Votes:
              3 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development