DisplayTag
  1. DisplayTag
  2. DISPL-263

Session-enabled display tag library

    Details

    • Type: New Feature New Feature
    • Status: Closed Closed
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 1.1
    • Fix Version/s: 1.2
    • Component/s: Paging/Sorting
    • Labels:
      None
    • Application server:
      Tomcat 5.0.28

      Description

                                                                                      Session-enabled display tag library
      ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
      The display tag library is not session-enabled i.e., the sorting and paginnation is not preserved across the session. Sometimes its desirable that the previously selected sorting or page is shown again to the user when the user revists a page. To make display tag library session-aware we did the following changes:

      org.displaytag.tags.TableTag class
      ---------------------------------------------

      The initParameters( ) method of TableTag class encodes the current page number, sort column index and sort order and stores it in instance variables. These instance variables form part of the request URL to ensure that the sorting ( ascending / descending ) is preserved across multiple interaction with the table shown on the web page. To encode current page number, sort column index and sort order, the TableTag class makes use of the encodeParameter ( .. ) method, which accepts a prefix to be used when encoding a parameter. The following code from org.displaytag.tags.TagTagParameters class shows the values that are passed to the encodeParameter ( ... )method:

          /**
           * name of the parameter specifying the current sorted column index.
           */
          public static final String PARAMETER_SORT = "s"; //$NON-NLS-1$

          /**
           * name of the parameter specifying the current page number.
           */
          public static final String PARAMETER_PAGE = "p"; //$NON-NLS-1$

          /**
           * name of the parameter specifying the current sorting order.
           */
          public static final String PARAMETER_ORDER = "o"; //$NON-NLS-1$

      The encodeParameter (...s) method makes use of org.displaytag.util.ParamEncoder class to generate unique parameter names. The contructor of ParamEncoder class accepts a unique id. This unique id is nothing but the uid attribute of <display:table> tag. The display tag documentation mentions that two tables on the same page MUST NOT have same uid, because if you keep them same then it won't be possible for the display tag library to distinguish between the two tables.

      If two tables on the same web page have same uid then the actions taken on one table will apply on the other table also because display tag won't be able to distinguish between the two tables. If the uid for two tables ( on the same web page ) are different then the encodeParameter method will create different unique parameter names because it makes use of uid attribute when generating parameter names.

      Note: We earlier modified the display tag library to fix problem related to pagination because of which our first page is designated as 1. If you are using the fixes provided by display tag team then instead of 1, use 0 before using the code below.
      When using display tag you may have seen something like the following in the URL:

      d-49653-p=1&d-49653-o=2&d-49653-s=2

      d-49653-p - encoded parameter corresponding to the current page number
      d-49653-o - encoded parameter corresponding to the sort order
      d-49653-s - encoded parameter corresponding to the sort column

      The p, o and s in the encoded parameter comes from the constants defined in TableTagParameters ( see above ).

      Problems involved in making display tag library session-aware

      • Adding the encoded parameter name and value into the session
      • Lets say a user moves from web page A ( which contains table T1 ) to a web page B ( which contains table T2 ). If T1 and T2 tables have the same uid attribute then the resulting encoded parameter names will have the same name i.e., if on web page B we add encoded parameter name and value corresponding to table T2 in the session then it will overwrite the encoded parameter corresponding to the table T1.
      • If it is required to remove the encoded parameters from the session then how a developer can generate the encoded parameter names programmatically.

      Adding the encoded parameter name and value into the session

      The initParameter( ) method of TableTag was modified to add the encoded parameter name and value into the session:
       
      • Adding encoded page parameter to the session

      Integer pageNumberParameter = requestHelper.getIntParameter(encodeParameter(TableTagParameters.PARAMETER_PAGE));
      if(pageNumberParameter == null) {
      // If the encoded page parameter exists in the session then obtain its value.
      // Else add the encoded page parameter to the session and sets its value to 1.
      Object objPageParameter = this.pageContext.getSession().getAttribute(encodeParameter(TableTagParameters.PARAMETER_PAGE));
      if(objPageParameter != null) {
      pageNumberParameter = (Integer)objPageParameter;
      } else {
      pageNumberParameter = new Integer(1);
      this.pageContext.getSession().setAttribute(encodeParameter(TableTagParameters.PARAMETER_PAGE), pageNumberParameter);
      }
      }
      this.pageContext.getSession().setAttribute(encodeParameter(TableTagParameters.PARAMETER_PAGE), pageNumberParameter);
      this.pageNumber = pageNumberParameter.intValue();


      Integer sortColumnParameter = requestHelper.getIntParameter(encodeParameter(TableTagParameters.PARAMETER_SORT));
      if( sortColumnParameter == null ) {
      Object objSortParameter = this.pageContext.getSession().getAttribute(encodeParameter(TableTagParameters.PARAMETER_SORT));
      if( objSortParameter != null ) {
      sortColumnParameter = (Integer)objSortParameter;
      } else {
      sortColumnParameter = new Integer(this.defaultSortedColumn);
      this.pageContext.getSession().setAttribute(encodeParameter(TableTagParameters.PARAMETER_SORT), sortColumnParameter);
      }
      }
      this.pageContext.getSession().setAttribute(encodeParameter(TableTagParameters.PARAMETER_SORT), sortColumnParameter);
      int sortColumn = sortColumnParameter.intValue();


      Integer sortColumnParameter = requestHelper.getIntParameter(encodeParameter(TableTagParameters.PARAMETER_SORT));
      if( sortColumnParameter == null ) {
      Object objSortParameter = this.pageContext.getSession().getAttribute(encodeParameter(TableTagParameters.PARAMETER_SORT));
      if( objSortParameter != null ) {
      sortColumnParameter = (Integer)objSortParameter;
      } else {
      sortColumnParameter = new Integer(this.defaultSortedColumn);
      this.pageContext.getSession().setAttribute(encodeParameter(TableTagParameters.PARAMETER_SORT), sortColumnParameter);
      }
      }
      this.pageContext.getSession().setAttribute(encodeParameter(TableTagParameters.PARAMETER_SORT),sortColumnParameter);
      int sortColumn = sortColumnParameter.intValue();


      Integer sortCode = requestHelper.getIntParameter(encodeParameter(TableTagParameters.PARAMETER_ORDER));
      SortOrderEnum paramOrder = SortOrderEnum.fromCode(sortCode);
      if(paramOrder == null) {
      Object objSortParameter =
      this.pageContext.getSession().getAttribute(encodeParameter(TableTagParameters.PARAMETER_ORDER));
      if(objSortParameter != null) {
      paramOrder = (SortOrderEnum)objSortParameter;
      } else {
      paramOrder = this.defaultSortOrder;
      }
      }
      this.pageContext.getSession().setAttribute(encodeParameter(TableTagParameters.PARAMETER_ORDER), paramOrder);

      Differentiating two tables on different web pages with same uid

      To take care of this situation we modified the ParamEncoder class constructor to accept 'requestURI' ( you can use 'uid' attribute instead ) attribute value also.
      private String encodeParameter(String parameterName) {
              // paramEncoder has been already instantiated?
              if (this.paramEncoder == null)
              {
                   // use the id attribute to get the unique identifier
                   // If the <display:table> tag encloses another <display:table> then pass this information to ParamEncoder to ensure
                  // different encoded parameter is generated.
                   TableTag tableTag = (TableTag)findAncestorWithClass(this, TableTag.class);
                  HttpServletRequest request = (HttpServletRequest)this.pageContext.getRequest();
                   if(tableTag != null) {
      this.paramEncoder = new ParamEncoder(getUid(), true, requestUri);
                    } else {
      this.paramEncoder = new ParamEncoder(getUid(), false, requestUri);
      }
              }
              return this.paramEncoder.encodeParameterName(parameterName);
      }

      public ParamEncoder(String idAttribute, boolean parentFound, String uri)
      {
      // use name and id to get the unique identifier
               String stringIdentifier = "x-" + idAttribute; //$NON-NLS-1$
               if(uri != null) {
      stringIdentifier = stringIdentifier + uri;
      }
              ....
      ....
      if( parentFound ) {
      this.parameterIdentifier = "z-" + checkSum + "-"; //$NON-NLS-1$ //$NON-NLS-2$
           } else {
      this.parameterIdentifier = "d-" + checkSum + "-"; //$NON-NLS-1$ //$NON-NLS-2$
      }
          }

      Removing encoded parameters from the session

      Lets say that you use display tag to show 10 records per page. If there are 15 records then two page will be shown to the user. The problem occurs when the user has the option to delete records from the table shown. If the user deletes the last 5 records from the last page then the session is corrupted because encoded parameter for the page number will refer to the last page i.e, 2nd page, which no longer exists. Its been observed that this results in distorted table being shown to the user. In such cases it is required that the encoded page number parameter should be set to the second last page. The simplest way to take care of this is to do the following in your JSP page ( using scriptlet or JSTL ) :

      if((recordCount % 10 == 0) && !code.equals("coursemap.delete.required")) {
      Enumeration names = session.getAttributeNames();
      while(names.hasMoreElements()) {
      String name = (String)names.nextElement();
      if((name.startsWith("d-") && name.endsWith("-p")) || (name.startsWith("z-") && name.endsWith("-p"))) {
          int value = ((Integer)session.getAttribute(name)).intValue();
      if(value > 1) {
      session.setAttribute(name, new Integer(value-1));
      } else {
      session.removeAttribute(name);
      }
      }
      }
      }

      Summary:

      This is really not a great solution because we modified the existing display tag code to make it session-aware. Ideally, there should be an attribute defined in the <display:table> tag which should specify whether user wants Pagination/Sorting function to be session-enabled or not. Also it should provide some simpler way to get to know the name of the session attribute which stores the sort order, current page number, sort column index, so that a user doesnt need to iterate over the session attributes to remove it.
      1. DisplaytagColumnSortFilter.java
        3 kB
        Mikkel Heisterberg
      2. ParamEncoder.java
        3 kB
        Ashish Sarin
      3. TableTag.java
        60 kB
        Ashish Sarin

        Activity

        Hide
        Ashish Sarin added a comment -
        Modified TableTag.java file
        Show
        Ashish Sarin added a comment - Modified TableTag.java file
        Hide
        Ashish Sarin added a comment -
        Modified ParamEncoder.java file
        Show
        Ashish Sarin added a comment - Modified ParamEncoder.java file
        Hide
        Mikkel Heisterberg added a comment -
        I implemented this behaviour (for sort column and sort order) using a servlet filter in a servlet/jsp application using displaytag 1.0. I find this sufficient and I wouldn't want it added to the codebase. Adding support for pagination should be trivial.

        I will attach the filter (DisplaytagColumnSortFilter.java).
        Show
        Mikkel Heisterberg added a comment - I implemented this behaviour (for sort column and sort order) using a servlet filter in a servlet/jsp application using displaytag 1.0. I find this sufficient and I wouldn't want it added to the codebase. Adding support for pagination should be trivial. I will attach the filter (DisplaytagColumnSortFilter.java).
        Hide
        Marianne Lund added a comment -
        I disagree with the priority level on this bug - in many cases you wish to come back to the same page not having to redo sorting or paging. I think that displaytag should be user friendly also in applications of some complexity. When can I see this functionality added into a standard release?
        Show
        Marianne Lund added a comment - I disagree with the priority level on this bug - in many cases you wish to come back to the same page not having to redo sorting or paging. I think that displaytag should be user friendly also in applications of some complexity. When can I see this functionality added into a standard release?
        Hide
        Jose Lima added a comment -
        I have an application running in Spring and using displaytag. In some screens there are lists of elements with pagination and options to edit an entry.

        After editing an entry in any page it is desired to be placed back on the same page, instead of always the first - which occurs now.

        I though about using this patch to solve the problem, but I wonder if there is something in the actual code (version 1.1) that would be more advisable to use?

        Many thanks in advance for any help,


        Show
        Jose Lima added a comment - I have an application running in Spring and using displaytag. In some screens there are lists of elements with pagination and options to edit an entry. After editing an entry in any page it is desired to be placed back on the same page, instead of always the first - which occurs now. I though about using this patch to solve the problem, but I wonder if there is something in the actual code (version 1.1) that would be more advisable to use? Many thanks in advance for any help,
        Hide
        Joachim added a comment -
        I agree with Marianne.

        Please add such a feature (it's a duplicate of DISPL-125, http://jira.codehaus.org/browse/DISPL-125) to displaytag.

        Thanks.
        Show
        Joachim added a comment - I agree with Marianne. Please add such a feature (it's a duplicate of DISPL-125 , http://jira.codehaus.org/browse/DISPL-125) to displaytag. Thanks.
        Hide
        fabrizio giustina added a comment -
        Closing as a duplicate of DISPL-125
        stay tuned, this feature will soon be released as part of displaytag 1.1.2 ;)
        Show
        fabrizio giustina added a comment - Closing as a duplicate of DISPL-125 stay tuned, this feature will soon be released as part of displaytag 1.1.2 ;)

          People

          • Reporter:
            Anonymous
          • Votes:
            6 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Time Tracking

              Estimated:
              Original Estimate - 5 days
              5d
              Remaining:
              Remaining Estimate - 5 days
              5d
              Logged:
              Time Spent - Not Specified
              Not Specified