MyFaces Core
  1. MyFaces Core
  2. MYFACES-454

UIViewRoot#createUniqueId() does not return an unique id in Portlet environment.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.1.0
    • Fix Version/s: 1.1.0
    • Component/s: General
    • Labels:
      None
    • Environment:
      Apache Portals Jetspeed2 2.0-M4-SNAPSHOT

      Description

      In Portlet environment, if you put multiple portlets created by MyFaces to one page, the duplicated id is used on each portlets.

      1. UIViewRoot.patch
        1 kB
        Shinsuke Sugaya

        Activity

        Hide
        Shinsuke Sugaya added a comment -

        Attached patch.
        The Portlet spec(JSR 168) defines the name space in PLT.12.3.4.

        Show
        Shinsuke Sugaya added a comment - Attached patch. The Portlet spec(JSR 168) defines the name space in PLT.12.3.4.
        Hide
        Martin Marinschek added a comment -

        Thanks to Shinsuke Sugaya for supplying this patch

        Show
        Martin Marinschek added a comment - Thanks to Shinsuke Sugaya for supplying this patch
        Hide
        Stan Silvert added a comment -

        This patch will break non-portlet environments that do not include the portlet jar. You will get a ClassDefNotFound exception when you try to do "instanceof RenderResponse". I will fix it the correct way using PortletUtil.

        Show
        Stan Silvert added a comment - This patch will break non-portlet environments that do not include the portlet jar. You will get a ClassDefNotFound exception when you try to do "instanceof RenderResponse". I will fix it the correct way using PortletUtil.
        Hide
        Stan Silvert added a comment -

        Actually, you can't use PortletUtil from here because this is the API code which is not allowed to reference the MyFaces impl code. The proper way to fix this is to call ExternalContext.encodeNamespace().

        Show
        Stan Silvert added a comment - Actually, you can't use PortletUtil from here because this is the API code which is not allowed to reference the MyFaces impl code. The proper way to fix this is to call ExternalContext.encodeNamespace().
        Hide
        Stan Silvert added a comment -

        Fix has been committed. We need Shinsuke to test before we close this.

        Show
        Stan Silvert added a comment - Fix has been committed. We need Shinsuke to test before we close this.
        Hide
        Phanidhar Adusumilli added a comment -

        Based on JSF specification section 3.1.6 and Portlet Specification section 12.3.4, MyFaces implementation (UIViewRoot and UIComponentBase) do not provide unique client id's.

        In the current implementation(s) (1.1.1 & 1.1.2)

        UIViewRoot.createUniqueId() is implemented as follows:

        /* Provides a unique id for this component instance.
        */
        public String createUniqueId()

        { ExternalContext extCtx = FacesContext.getCurrentInstance().getExternalContext(); return extCtx.encodeNamespace(UNIQUE_ID_PREFIX + _uniqueIdCounter++); }

        This makes the id unique for a component, but while rendering the clientId is used.
        Problem1:
        With this the namespace is repeated for every component.
        For example:
        if the jsp is as follows:

        <h:form>
        <h:inputtext .../>
        </h:form>

        the id of the form in the markup will be portlet1_id0
        and the id of the inputtext will be portlet1_id0:portlet1_id1.

        The namespace is unecesarily repeated.

        Problem2:
        The above implementation will not make the id, in the generated markup unique if the id is specified in the jsp.

        For example:
        <h:form id="Myform">
        <h:inputtext id="name" .../>
        </h:form>

        the id of the form in the markup will be Myform
        and the id of the inputtext will be Myform:name.

        This does not make them unique in portal environment because createUniqueId is never called.

        My opinion is that the fix should be in UIComponentBase.getClientId() not in UIViewRoot.createUniqueId().

        getClientId() must return the namespace encoded client id.

        With this
        for Problem1:

        the id's would be portlet1_id0 and portlet1_id0:_id1

        for Problem2:

        the id's would be portlet1_Myform and portlet1_Myform:name.

        I would appreciate comments on this from MyFaces developers.

        Show
        Phanidhar Adusumilli added a comment - Based on JSF specification section 3.1.6 and Portlet Specification section 12.3.4, MyFaces implementation (UIViewRoot and UIComponentBase) do not provide unique client id's. In the current implementation(s) (1.1.1 & 1.1.2) UIViewRoot.createUniqueId() is implemented as follows: /* Provides a unique id for this component instance. */ public String createUniqueId() { ExternalContext extCtx = FacesContext.getCurrentInstance().getExternalContext(); return extCtx.encodeNamespace(UNIQUE_ID_PREFIX + _uniqueIdCounter++); } This makes the id unique for a component, but while rendering the clientId is used. Problem1: With this the namespace is repeated for every component. For example: if the jsp is as follows: <h:form> <h:inputtext .../> </h:form> the id of the form in the markup will be portlet1_id0 and the id of the inputtext will be portlet1_id0:portlet1_id1. The namespace is unecesarily repeated. Problem2: The above implementation will not make the id, in the generated markup unique if the id is specified in the jsp. For example: <h:form id="Myform"> <h:inputtext id="name" .../> </h:form> the id of the form in the markup will be Myform and the id of the inputtext will be Myform:name. This does not make them unique in portal environment because createUniqueId is never called. My opinion is that the fix should be in UIComponentBase.getClientId() not in UIViewRoot.createUniqueId(). getClientId() must return the namespace encoded client id. With this for Problem1: the id's would be portlet1_id0 and portlet1_id0:_id1 for Problem2: the id's would be portlet1_Myform and portlet1_Myform:name. I would appreciate comments on this from MyFaces developers.
        Hide
        Shinsuke Sugaya added a comment -

        See Phanidhar's comment. UIComponentBase.getClientId() needs to be modified.

        Show
        Shinsuke Sugaya added a comment - See Phanidhar's comment. UIComponentBase.getClientId() needs to be modified.
        Hide
        Leonardo Uribe added a comment -

        This was fixed with the standarization of portlet-brigde. A custom UIViewRoot is used in that case that implements NamingContainer interface, preventing duplicate ids. I'll close this issue as fixed.

        Show
        Leonardo Uribe added a comment - This was fixed with the standarization of portlet-brigde. A custom UIViewRoot is used in that case that implements NamingContainer interface, preventing duplicate ids. I'll close this issue as fixed.

          People

          • Assignee:
            Stan Silvert
            Reporter:
            Shinsuke Sugaya
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development