Session-enabled display tag library ----------------------------------- Key: DISPL-263 URL: http://jira.codehaus.org/browse/DISPL-263 Project: DisplayTag Type: New Feature Components: Paging/Sorting Versions: 1.1 Priority: Minor Attachments: ParamEncoder.java, TableTag.java
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. -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://jira.codehaus.org/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira ------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Do you grep through log files for problems? Stop! Download the new AJAX search engine that makes searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! http://ads.osdn.com/?ad_idv37&alloc_id865&op=click _______________________________________________ displaytag-devel mailing list displaytag-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/displaytag-devel