title: Order of the selected rows are not remembered when I refresh a JSF page
body: <p>I have a very strange bug into jsf page which I cannot find. This is the code of the JSF page:</p>
  
  <pre><code>&lt;?xml version='1.0' encoding='UTF-8' ?&gt;
  &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
  &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"    
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:ui="http://java.sun.com/jsf/facelets"&gt;
      &lt;h:head&gt;
          &lt;ui:insert name="header"&gt;           
              &lt;ui:include src="header.xhtml"/&gt;         
          &lt;/ui:insert&gt;
      &lt;/h:head&gt;
      &lt;h:body&gt;
  
          &lt;h1&gt;&lt;img src="resources/css/images/icon.png" alt="DX-57" /&gt; History Center&lt;/h1&gt;
          &lt;!-- layer for black background of the buttons --&gt;
          &lt;div id="toolbar" style="margin: 0 auto; width:1180px; height:30px; position:relative;  background-color:black"&gt;
              &lt;!-- Include page Navigation --&gt;
              &lt;ui:insert name="Navigation"&gt;           
                  &lt;ui:include src="Navigation.xhtml"/&gt;         
              &lt;/ui:insert&gt;
  
          &lt;/div&gt;  
  
          &lt;div id="logodiv" style="position:relative; top:35px; left:0px;"&gt; 
              &lt;h:graphicImage alt="Dashboard"  style="position:relative; top:-20px; left:9px;"  value="resources/images/logo_sessions.png" /&gt;
          &lt;/div&gt;
          &lt;div id="main" style="margin: 0 auto; width:1190px; height:700px; position:absolute;  background-color:transparent; top:105px"&gt;
  
              &lt;div id="mainpage" style="margin: 0 auto; width:1190px; height:500px; position:absolute;  background-color:transparent; top:80px"&gt;
  
                  &lt;div id="settingsHashMap" style="width:750px; height:400px; position:absolute;  background-color:r; top:20px; left:1px"&gt;
  
                      &lt;h:form id="form"&gt;
  
                          &lt;ui:debug /&gt;
  
                          &lt;!-- The sortable data table --&gt;
                          &lt;h:dataTable id="dataTable" value="#{SessionsController.dataList}" binding="#{table}" var="item"&gt;
                              &lt;!-- Check box --&gt;
                              &lt;h:column&gt;
                                  &lt;f:facet name="header"&gt;
                                      &lt;h:outputText value="Select" /&gt;
                                  &lt;/f:facet&gt;
                                  &lt;h:selectBooleanCheckbox onclick="highlight(this)" value="#{SessionsController.selectedIds[item.aSessionID]}" /&gt;
                              &lt;/h:column&gt;
                              &lt;h:column&gt;
                                  &lt;f:facet name="header"&gt;
                                      &lt;h:commandLink value="№" actionListener="#{SessionsController.sort}"&gt;
                                          &lt;f:attribute name="№" value="№" /&gt;
                                      &lt;/h:commandLink&gt;
                                  &lt;/f:facet&gt;
                                  &lt;h:outputText value="#{table.rowIndex + SessionsController.firstRow + 1}" /&gt;
                              &lt;/h:column&gt;
                              &lt;h:column&gt;
                                  &lt;f:facet name="header"&gt;
                                      &lt;h:commandLink value="Account Session ID" actionListener="#{SessionsController.sort}"&gt;
                                          &lt;f:attribute name="sortField" value="Account Session ID" /&gt;
                                      &lt;/h:commandLink&gt;
                                  &lt;/f:facet&gt;
                                  &lt;h:outputText value="#{item.aSessionID}" /&gt;
                              &lt;/h:column&gt;
                              &lt;h:column&gt;
                                  &lt;f:facet name="header"&gt;
                                      &lt;h:commandLink value="User ID" actionListener="#{SessionsController.sort}"&gt;
                                          &lt;f:attribute name="sortField" value="User ID" /&gt;
                                      &lt;/h:commandLink&gt;
                                  &lt;/f:facet&gt;
                                  &lt;h:outputText value="#{item.userID}" /&gt;
                              &lt;/h:column&gt;
                              &lt;h:column&gt;
                                  &lt;f:facet name="header"&gt;
                                      &lt;h:commandLink value="Activity Start Time" actionListener="#{SessionsController.sort}"&gt;
                                          &lt;f:attribute name="sortField" value="Activity Start Time" /&gt;
                                      &lt;/h:commandLink&gt;
                                  &lt;/f:facet&gt;
                                  &lt;h:outputText value="#{item.activityStart}" /&gt;
                              &lt;/h:column&gt;
                              &lt;h:column&gt;
                                  &lt;f:facet name="header"&gt;
                                      &lt;h:commandLink value="Activity End Time" actionListener="#{SessionsController.sort}"&gt;
                                          &lt;f:attribute name="sortField" value="Activity End Time" /&gt;
                                      &lt;/h:commandLink&gt;
                                  &lt;/f:facet&gt;
                                  &lt;h:outputText value="#{item.activityEnd}" /&gt;
                              &lt;/h:column&gt;
                              &lt;h:column&gt;
                                  &lt;f:facet name="header"&gt;
                                      &lt;h:commandLink value="Activity" actionListener="#{SessionsController.sort}"&gt;
                                          &lt;f:attribute name="sortField" value="Activity" /&gt;
                                      &lt;/h:commandLink&gt;
                                  &lt;/f:facet&gt;
                                  &lt;h:outputText value="#{item.activity}" /&gt;
                              &lt;/h:column&gt;
                          &lt;/h:dataTable&gt;
  
                          &lt;!-- The paging buttons --&gt;
                          &lt;h:commandButton value="first" action="#{SessionsController.pageFirst}"
                                           disabled="#{SessionsController.firstRow == 0}" &gt;
                              &lt;f:ajax render="@form" execute="@form"&gt;&lt;/f:ajax&gt;
                          &lt;/h:commandButton&gt;
  
  
                          &lt;h:commandButton value="prev" action="#{SessionsController.pagePrevious}"
                                           disabled="#{SessionsController.firstRow == 0}" &gt;
                              &lt;f:ajax render="@form" execute="@form"&gt;&lt;/f:ajax&gt;
                          &lt;/h:commandButton&gt;
  
                          &lt;h:commandButton value="next" action="#{SessionsController.pageNext}"
                                           disabled="#{SessionsController.firstRow + SessionsController.rowsPerPage &gt;= SessionsController.totalRows}" &gt;
                              &lt;f:ajax render="@form" execute="@form"&gt;&lt;/f:ajax&gt;
                          &lt;/h:commandButton&gt;    
  
                          &lt;h:commandButton value="last" action="#{SessionsController.pageLast}"
                                           disabled="#{SessionsController.firstRow + SessionsController.rowsPerPage &gt;= SessionsController.totalRows}" &gt;
                              &lt;f:ajax render="@form" execute="@form"&gt;&lt;/f:ajax&gt;
                          &lt;/h:commandButton&gt;
  
                          &lt;h:outputText value="Page #{SessionsController.currentPage} / #{SessionsController.totalPages}" /&gt;
                          &lt;br /&gt;
  
                          &lt;!-- The paging links --&gt;
                          &lt;ui:repeat value="#{SessionsController.pages}" var="page"&gt;
                              &lt;h:commandLink value="#{page}" actionListener="#{SessionsController.page}"
                                             rendered="#{page != SessionsController.currentPage}" &gt;
                                  &lt;f:ajax render="@form" execute="@form"&gt;&lt;/f:ajax&gt;   
                              &lt;/h:commandLink&gt;
                              &lt;h:outputText value="#{page}" escape="false"
                                            rendered="#{page == SessionsController.currentPage}" /&gt;
                          &lt;/ui:repeat&gt;
                          &lt;br /&gt;
  
                          &lt;!-- Set rows per page --&gt;
                          &lt;h:outputLabel for="rowsPerPage" value="Rows per page" /&gt;
                          &lt;h:inputText id="rowsPerPage" value="#{SessionsController.rowsPerPage}" size="3" maxlength="3" /&gt;
                          &lt;h:commandButton value="Set" action="#{SessionsController.pageFirst}" &gt;
                              &lt;f:ajax render="@form" execute="@form"&gt;&lt;/f:ajax&gt;
                          &lt;/h:commandButton&gt;
                          &lt;h:message for="rowsPerPage" errorStyle="color: red;" /&gt;
  
                          &lt;h:commandButton value="Delete" action="#{SessionsController.deleteSelectedIDs}" &gt;
                              &lt;f:ajax render="@form" execute="@form"&gt;&lt;/f:ajax&gt;
                          &lt;/h:commandButton&gt;
  
                          &lt;script type="text/javascript"&gt;
                              $("tr").not(':first').hover(
                              function () {
                                  $(this).css("background","#707070");
                              }, 
                              function () {
                                  $(this).css("background","");
                              }
                          );              
  
                              function highlight(param) {  
                                  var row = jQuery(param).parent().parent().children();
                                  row.toggleClass('highlited');
                              }        
                          &lt;/script&gt;
  
  
                      &lt;/h:form&gt;                  
  
                  &lt;/div&gt;   
  
                  &lt;div id="settingsdivb" style="width:350px; height:400px; position:absolute;  background-color:transparent; top:20px; left:800px"&gt;
  
                  &lt;/div&gt;   
              &lt;/div&gt;  
          &lt;/div&gt;
  
      &lt;/h:body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>This is the managed bean:</p>
  
  <pre><code>import java.io.Serializable;
  import javax.enterprise.context.SessionScoped;
  // or import javax.faces.bean.SessionScoped;
  import javax.inject.Named;
  /*
   * include SQL Packages
   */
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.util.*;
  import javax.annotation.PostConstruct;
  import javax.sql.DataSource;
  import javax.annotation.Resource;
  import javax.faces.bean.ViewScoped;
  import javax.faces.component.UICommand;
  import javax.faces.context.FacesContext;
  import javax.inject.Inject;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
  // or import javax.faces.bean.ManagedBean; 
  import javax.faces.event.ActionEvent;
  
  import org.glassfish.osgicdi.OSGiService;
  
  @Named("SessionsController")
  @ViewScoped
  public class Sessions implements Serializable {
  
      /*
       * Call the Oracle JDBC Connection driver
       */
      @Resource(name = "jdbc/Oracle")
      private DataSource ds;
      // Data.
      private List&lt;ActiveSessionObj&gt; dataList;
      // Rows
      private int totalRows;
      // Paging.
      private static int firstRow;
      private int rowsPerPage;
      private int totalPages;
      private int pageRange;
      private Integer[] pages;
      private int currentPage;
      // Sorting.
      private String sortField;
      private boolean sortAscending;
  
      /*
       * Constructor
       */
      public Sessions() {
          /*
           * Set default properties
           */
          rowsPerPage = 10; // Default rows per page (max amount of rows to be displayed at once).
          pageRange = 10; // Default page range (max amount of page links to be displayed at once).
          sortField = "ASESSIONID"; // Default sort field.
          sortAscending = true; // Default sort direction.
      }
  
      public class ActiveSessionObj {
  
          private String aSessionID;
          private String userID;
          private Date activityStart;
          private Date activityEnd;
          private String activity;
          //private boolean selected;
  
          public ActiveSessionObj(String aSessionID, String userID, Date activityStart, Date activityEnd, String activity) {
              this.aSessionID = aSessionID;
              this.userID = userID;
              this.activityStart = activityStart;
              this.activityEnd = activityEnd;
              this.activity = activity;
          }
  
          public int getFirstRow() {
              return firstRow;
          }
  
          public String getaSessionID() {
              return aSessionID;
          }
  
          public void setaSessionID(String aSessionID) {
              this.aSessionID = aSessionID;
          }
  
          public String getactivity() {
              return activity;
          }
  
          public void setactivity(String activity) {
              this.activity = activity;
          }
  
          public Date getactivityEnd() {
              return activityEnd;
          }
  
          public void setactivityEnd(Date activityEnd) {
              this.activityEnd = activityEnd;
          }
  
          public Date getactivityStart() {
              return activityStart;
          }
  
          public void setactivityStart(Date activityStart) {
              this.activityStart = activityStart;
          }
  
          public String getuserID() {
              return userID;
          }
  
          public void setuserID(String userID) {
              this.userID = userID;
          }
  
          private ActiveSessionObj() {
              throw new UnsupportedOperationException("Not yet implemented");
          }
      }
  
      // Paging actions -----------------------------------------------------------------------------
      public void pageFirst() {
          page(0);
      }
  
      public void pageNext() {
          page(firstRow + rowsPerPage);
      }
  
      public void pagePrevious() {
          page(firstRow - rowsPerPage);
      }
  
      public void pageLast() {
          page(totalRows - ((totalRows % rowsPerPage != 0) ? totalRows % rowsPerPage : rowsPerPage));
      }
  
      public void page(ActionEvent event) {
          page(((Integer) ((UICommand) event.getComponent()).getValue() - 1) * rowsPerPage);
      }
  
      private void page(int firstRow) {
          this.firstRow = firstRow;
          loadDataList(); // Load requested page.
      }
  
      // Sorting actions ----------------------------------------------------------------------------
      public void sort(ActionEvent event) {
          String sortFieldAttribute = (String) event.getComponent().getAttributes().get("sortField");
  
          // If the same field is sorted, then reverse order, else sort the new field ascending.
          if (sortField.equals(sortFieldAttribute)) {
              sortAscending = !sortAscending;
          } else {
              sortField = sortFieldAttribute;
              sortAscending = true;
          }
  
          pageFirst(); // Go to first page and load requested page.
      }
  
      // Loaders ------------------------------------------------------------------------------------
      private void loadDataList() {
  
          // Load list and totalCount.
          try {
              dataList = list(firstRow, rowsPerPage, sortField, sortAscending);
              totalRows = countDBRowNum(); //count the tablerows
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
  
          // Set currentPage, totalPages and pages.
          currentPage = (totalRows / rowsPerPage) - ((totalRows - firstRow) / rowsPerPage) + 1;
          totalPages = (totalRows / rowsPerPage) + ((totalRows % rowsPerPage != 0) ? 1 : 0);
          int pagesLength = Math.min(pageRange, totalPages);
          pages = new Integer[pagesLength];
  
          // firstPage must be greater than 0 and lesser than totalPages-pageLength.
          int firstPage = Math.min(Math.max(0, currentPage - (pageRange / 2)), totalPages - pagesLength);
  
          // Create pages (page numbers for page links).
          for (int i = 0; i &lt; pagesLength; i++) {
              pages[i] = ++firstPage;
          }
      }
  
      // Getters ------------------------------------------------------------------------------------
      public List&lt;ActiveSessionObj&gt; getdataList() {
          if (dataList == null) {
              loadDataList(); // Preload page for the 1st view.
          }
          return dataList;
      }
  
      public int getTotalRows() {
          return totalRows;
      }
  
      public int getFirstRow() {
          return firstRow;
      }
  
      public int getRowsPerPage() {
          return rowsPerPage;
      }
  
      public Integer[] getPages() {
          return pages;
      }
  
      public int getCurrentPage() {
          return currentPage;
      }
  
      public int getTotalPages() {
          return totalPages;
      }
  
      // Setters ------------------------------------------------------------------------------------
      public void setRowsPerPage(int rowsPerPage) {
          this.rowsPerPage = rowsPerPage;
      }
  
      // Actions ------------------------------------------------------------------------------------
      /**
       * Returns list of ActiveSessionObj items starting at the given first index
       * with the given row count, sorted by the given sort field and sort order.
       *
       * @param firstRow First index of rows to be returned.
       * @param rowCount Amount of rows to be returned.
       * @param sortField Field to sort the data on.
       * @param sortAscending Whether to sort data ascending or not.
       * @return list of ActiveSessionObj items starting at the given first index
       * with the given row count, sorted by the given sort field and sort order.
       */
      public List&lt;ActiveSessionObj&gt; list(int firstRow, int rowCount, String sortField, boolean sortAscending) throws SQLException {
  
          String SqlStatementSmall = null;
          String SQLStatementLarge = null;
  
          if (ds == null) {
              throw new SQLException();
          }
  
          Connection conn = ds.getConnection();
          if (conn == null) {
              throw new SQLException();
          }
  
          int countrow = firstRow + rowCount;
          String sortDirection = sortAscending ? "ASC" : "DESC";
  
          /*
           * For small tables
           */
          SqlStatementSmall = "SELECT c.*"
                  + " FROM (SELECT b.*, rownum rn"
                  + " FROM (SELECT a.*"
                  + " FROM activeSessionsLog a"
                  + " ORDER BY %s %s) b"
                  + " WHERE rownum &lt;= ?) c"
                  + " WHERE rn &gt; ?";
  
          /*
           * For huge datatables optimized for perfomance
           */
          SQLStatementLarge = "select * from"
                  + " (select asl.*, row_number() over (order by userid asc) r "
                  + " from activesessionslog asl)"
                  + " where r &gt; 980750 and r &lt;= 980800;";
  
  
          String sql = String.format(SqlStatementSmall, sortField, sortDirection);
  
          PreparedStatement ps = null;
          ResultSet resultSet = null;
          List&lt;ActiveSessionObj&gt; dataList = new ArrayList&lt;ActiveSessionObj&gt;();
  
          try {
              conn.setAutoCommit(false);
              boolean committed = false;
  
              ps = conn.prepareStatement(sql);
              ps.setInt(1, countrow);
              ps.setInt(2, firstRow);
  
  
              resultSet = ps.executeQuery();
              /*
               * take the result from the SQL query and insert it into Array List
               * collection
               */
              dataList = ActiveSessionsArrayList(resultSet);
  
              conn.commit();
              committed = true;
  
          } finally {
              ps.close();
              conn.close();
          }
  
          return dataList;
      }
  
      public int countDBRowNum() throws Exception {
  
          String SqlStatement = null;
  
          if (ds == null) {
              throw new SQLException();
          }
  
          Connection conn = ds.getConnection();
          if (conn == null) {
              throw new SQLException();
          }
  
          SqlStatement = "SELECT count(*) FROM ACTIVESESSIONSLOG";
  
          PreparedStatement ps = null;
          ResultSet resultSet = null;
          int count = 0;
  
          try {
              conn.setAutoCommit(false);
              boolean committed = false;
              try {
                  SqlStatement = "SELECT count(*) FROM ACTIVESESSIONSLOG";
  
                  ps = conn.prepareStatement(SqlStatement);
                  resultSet = ps.executeQuery();
  
                  if (resultSet.next()) {
                      count = resultSet.getInt(1);
                  }
  
                  conn.commit();
                  committed = true;
              } finally {
                  if (!committed) {
                      conn.rollback();
                  }
              }
          } finally {
              ps.close();
              conn.close();
          }
          //Returns total amount of rows in table.
          return count;
      }
  
      /**
       * Map the current row of the given ResultSet to ActiveSessionObj.
       *
       * @param resultSet The ResultSet of which the current row is to be mapped
       * to ActiveSessionObj.
       * @return The mapped ActiveSessionObj from the current row of the given
       * ResultSet.
       */
      private ArrayList&lt;ActiveSessionObj&gt; ActiveSessionsArrayList(ResultSet rs) throws SQLException {
          ArrayList&lt;ActiveSessionObj&gt; list = new ArrayList&lt;&gt;();
  
  
          try {
              while (rs.next()) {
                  list.add(new ActiveSessionObj(
                          rs.getString("ASESSIONID"),
                          rs.getString("USERID"),
                          timestampToDate(rs.getTimestamp("ACTIVITYSTART")),
                          timestampToDate(rs.getTimestamp("ACTIVITYEND")),
                          rs.getString("ACTIVITY")));
              }
          } catch (Exception x) {
              x.printStackTrace();
          }
  
          return list;   
      }
  
      //get the selected rows
      private HashMap&lt;String, Boolean&gt; selectedIds = new HashMap&lt;&gt;();
  
      // get the list from the JSF page
      public Map&lt;String, Boolean&gt; getSelectedIds() {
          return selectedIds;
      }
  
      //delete all selected checkboxes
      public void deleteSelectedIDs() throws SQLException {
          boolean success = false;
  
          if (ds == null) {
              throw new SQLException();
          }
  
          Connection conn = ds.getConnection();
          if (conn == null) {
              throw new SQLException();
          }
  
          PreparedStatement ps = null;
          ResultSet resultSet = null;
  
          try {
              conn.setAutoCommit(false);
              boolean committed = false;
              try {
  
                  String sqlDeleteQuery = "DELETE FROM ACTIVESESSIONSLOG WHERE ASESSIONID = ?";
  
  
                  Set&lt;String&gt; keySet = selectedIds.keySet();
                  String[] keys = new String[]{};
                  keys = selectedIds.keySet().toArray(keys);
                  ps = conn.prepareStatement(sqlDeleteQuery);
  
                  for (int i = 0; i &lt; keys.length; i++) {
                      ps.setString(1, keys[i]);
                      ps.executeUpdate();
                      ps.clearParameters();
                      selectedIds.put(keys[i], false); //get(keys[i]) = false;
                  }
  
                  conn.commit();
                  committed = true;
  
                  //selectedIds.clear();
              } finally {
                  if (!committed) {
                      conn.rollback();
                  }
              }
          } finally {
              ps.close();
              conn.close();
          }
  
          /*
           * // Get selected items. boolean success = false; try { String
           * sqlDeleteQuery = "";
           *
           * Set&lt;String&gt; keySet = selectedIds.keySet(); Iterator keyIterator =
           * keySet.iterator(); while(keyIterator.hasNext()) { keyIterator.next();
           * }
           *
           * }
           * catch(Exception x) { success = false; } // Do your thing with the
           * MyData items in List selectedDataList.
           */
          //return success; // Navigation case.
  
          //reload the table
          loadDataList();
      }
  
      private static Date timestampToDate(java.sql.Timestamp ts) {
          Date d = null;
          try {
              d = new Date(ts.getTime());
          } catch (Exception e) {
              e.printStackTrace();
          }
  
          return d;
      }
  }
  </code></pre>
  
  <p>I opened the page and I select some rows I get this:
  <img src="https://i.stack.imgur.com/iCcKT.png" alt="enter image description here"></p>
  
  <p>But when I press F5 I'm redirected to page 1 </p>
  
  <p><img src="https://i.stack.imgur.com/psrCY.png" alt="enter image description here"></p>
  
  <p>It's very strange because the selected rows are changed. I use hash to remember which rows are selected. It seems that the position into the hashmap is changed.
  I changed to <code>static</code> the <code>firstrow</code> value into the managed bean. Then I get a second problem: the opened page is shared between the clients - when a second browser opens the page the same page of the pagination will be opened. </p>
  
  <p>I tested other solution - I changed the the scope of the bean to SessionScope. I removed the static variable. But the problem of the selected rows is not fixed. I still get the old problem with the position of the selected rows.</p>
  
  <p>Maybe the problem is the hashmap.</p>
  
  <p>private HashMap selectedIds = new HashMap&lt;>();</p>
  
  <p>I suspect that this hashmap is correct. The index of the row of the <code>h:datatable</code> must be remembered into the hashmap. How I can fix this problem?</p>
  
  <p>Best Wishes
  Peter</p>