title: Create JSF table with pagination and sorting
body: <p>I want to create <a href="http://balusc.blogspot.com/2008/10/effective-datatable-paging-and-sorting.html" rel="nofollow">this</a> JSF table with paging and sorting.</p>
  
  <p>This is JSF code so far:</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="NVIDIA.com" /&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="greenBand" class="ui-state-default ui-corner-allh" 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;!-- The sortable data table --&gt;
                          &lt;h:dataTable value="#{SessionsController.dataList}" var="item"&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;h:commandButton value="prev" action="#{SessionsController.pagePrevious}"
                                           disabled="#{SessionsController.firstRow == 0}" /&gt;
                          &lt;h:commandButton value="next" action="#{SessionsController.pageNext}"
                                           disabled="#{SessionsController.firstRow + SessionsController.rowsPerPage &gt;= SessionsController.totalRows}" /&gt;
                          &lt;h:commandButton value="last" action="#{SessionsController.pageLast}"
                                           disabled="#{SessionsController.firstRow + SessionsController.rowsPerPage &gt;= SessionsController.totalRows}" /&gt;
                          &lt;h:outputText value="Page #{SessionsController.currentPage} / #{SessionsController.totalPages}" /&gt;
                          &lt;br /&gt;
  
                          &lt;!-- The paging links --&gt;
                          &lt;t:dataList value="#{SessionsController.pages}" var="page"&gt;
                              &lt;h:commandLink value="#{page}" actionListener="#{SessionsController.page}"
                                             rendered="#{page != SessionsController.currentPage}" /&gt;
                              &lt;h:outputText value="&lt;b&gt;#{page}&lt;/b&gt;" escape="false"
                                            rendered="#{page == SessionsController.currentPage}" /&gt;
                          &lt;/t:dataList&gt;
                          &lt;h:form id="form"&gt;
  
                              &lt;!-- The sortable data table --&gt;
                              &lt;h:dataTable value="#{SessionsController.dataList}" var="item"&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;h:commandButton value="prev" action="#{SessionsController.pagePrevious}"
                                               disabled="#{SessionsController.firstRow == 0}" /&gt;
                              &lt;h:commandButton value="next" action="#{SessionsController.pageNext}"
                                               disabled="#{SessionsController.firstRow + SessionsController.rowsPerPage &gt;= SessionsController.totalRows}" /&gt;
                              &lt;h:commandButton value="last" action="#{SessionsController.pageLast}"
                                               disabled="#{SessionsController.firstRow + SessionsController.rowsPerPage &gt;= SessionsController.totalRows}" /&gt;
                              &lt;h:outputText value="Page #{SessionsController.currentPage} / #{SessionsController.totalPages}" /&gt;
                              &lt;br /&gt;
  
                              &lt;!-- The paging links --&gt;
                              &lt;t:dataList value="#{SessionsController.pages}" var="page"&gt;
                                  &lt;h:commandLink value="#{page}" actionListener="#{SessionsController.page}"
                                                 rendered="#{page != SessionsController.currentPage}" /&gt;
                                  &lt;h:outputText value="&lt;b&gt;#{page}&lt;/b&gt;" escape="false"
                                                rendered="#{page == SessionsController.currentPage}" /&gt;
                              &lt;/t:dataList&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;h:message for="rowsPerPage" errorStyle="color: red;" /&gt;
  
                              &lt;!-- Cache bean with data list, paging and sorting variables for next request --&gt;
                              &lt;t:saveState value="#{SessionsController}" /&gt;
                          &lt;/h:form&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;h:message for="rowsPerPage" errorStyle="color: red;" /&gt;
  
                          &lt;!-- Cache bean with data list, paging and sorting variables for next request --&gt;
                          &lt;t:saveState value="#{SessionsController}" /&gt;
                      &lt;/h:form&gt;
  
                  &lt;/div&gt;   
  
                  &lt;div id="settingsdiva" style="width:350px; height:400px; position:absolute;  background-color:transparent; top:20px; left:400px"&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>The Bean code:</p>
  
  <pre><code>import java.io.Serializable;
  import java.math.BigDecimal;
  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.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import javax.annotation.PostConstruct;
  import javax.sql.DataSource;
  import javax.annotation.Resource;
  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")
  @SessionScoped
  public class Sessions implements Serializable {
  
      /* Call the Oracle JDBC Connection driver */
      @Resource(name = "jdbc/Oracle")
      private DataSource ds;
      // DAO.
  //    private static ActiveSessionsDAO dao = DAOFactory.getInstance("javabase").getActiveSessionsDAO();
      // Data.
      private List&lt;ActiveSessions&gt; dataList;
      private int totalRows;
      // Paging.
      private int firstRow;
      private int rowsPerPage;
      private int totalPages;
      private int pageRange;
      private Integer[] pages;
      private int currentPage;
      // Sorting.
      private String sortField;
      private boolean sortAscending;
      // Constants ----------------------------------------------------------------------------------
      private static final String SQL_LIST_BY_ORDER_AND_LIMIT =
              "SELECT * FROM ACTIVESESSIONSLOG ORDER BY %s %s LIMIT ?, ?";
      private static final String SQL_COUNT =
              "SELECT count(*) FROM ACTIVESESSIONSLOG";
  
      private static class DAOFactory {
  
          public DAOFactory() {
          }
      }
  
      private static class ActiveSessions {
  
          public ActiveSessions() {
          }
  
          private ActiveSessions(long aLong, String string, Integer integer) {
              throw new UnsupportedOperationException("Not yet implemented");
          }
      }
      // Properties ---------------------------------------------------------------------------------
      private DAOFactory daoFactory;
  
      // Constructors -------------------------------------------------------------------------------
  
      Sessions(DAOFactory daoFactory) {
          this.daoFactory = daoFactory;
          // Set default values somehow (properties files?).
          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.
      }
  
      // 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 = dao.list(firstRow, rowsPerPage, sortField, sortAscending);
              totalRows = dao.count();
          } catch (Exception e) {
              throw new RuntimeException(e); // Handle it yourself.
          }
  
          // 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;ActiveSessions&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 ActiveSessions 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 ActiveSessions items starting at the given first index with the given row count,
       * sorted by the given sort field and sort order.
       * @throws DAOException If something fails at DAO level.
       */
      public List&lt;ActiveSessions&gt; list(int firstRow, int rowCount, String sortField, boolean sortAscending)
              throws Exception {
          Object[] values = {firstRow, rowCount};
  
          if (ds == null) {
              throw new SQLException();
          }
  
          String sortDirection = sortAscending ? "ASC" : "DESC";
          String sql = String.format(SQL_LIST_BY_ORDER_AND_LIMIT, sortField, sortDirection);
          Connection conn = ds.getConnection();
          PreparedStatement preparedStatement = null;
          ResultSet resultSet = null;
          List&lt;ActiveSessions&gt; dataList = new ArrayList&lt;ActiveSessions&gt;();
  
          try {
              conn.setAutoCommit(false);
              boolean committed = false;
  //            connection = daoFactory.getConnection();
              preparedStatement = conn.prepareStatement(sql);
              resultSet = preparedStatement.executeQuery();
              while (resultSet.next()) {
                  dataList.add(mapActiveSessions(resultSet));
              }
          } catch (SQLException e) {
              throw new Exception(e);
          } finally {
              conn.close();
          }
  
          return dataList;
      }
  
      /**
       * Returns total amount of rows in table.
       * @return Total amount of rows in table.
       * @throws DAOException If something fails at DAO level.
       */
      public int count() throws Exception {
  //        Connection connection = null;
          PreparedStatement preparedStatement = null;
          ResultSet resultSet = null;
          int count = 0;
  
          try {
  //            connection = daoFactory.getConnection();
              Connection conn = ds.getConnection();
              preparedStatement = conn.prepareStatement(SQL_COUNT);
              resultSet = preparedStatement.executeQuery();
              if (resultSet.next()) {
                  count = resultSet.getInt(1);
              }
          } catch (SQLException e) {
              throw new Exception(e);
          } finally {
              //close the connection
          }
  
          return count;
      }
  
      /**
       * Map the current row of the given ResultSet to ActiveSessions.
       * @param resultSet The ResultSet of which the current row is to be mapped to ActiveSessions.
       * @return The mapped ActiveSessions from the current row of the given ResultSet.
       * @throws SQLException If something fails at database level.
       */
      private static ActiveSessions mapActiveSessions(ResultSet resultSet) throws SQLException {
          return new ActiveSessions(
                  resultSet.getLong("ASESSIONID"),
                  resultSet.getString("USERID"),
                  resultSet.getObject("value") != null ? resultSet.getInt("value") : null);
                  /*
                  CREATE TABLE ACTIVESESSIONSLOG(
                      ASESSIONID VARCHAR2(30 ) NOT NULL,
                      USERID VARCHAR2(30 ),
                      ACTIVITYSTART TIMESTAMP(6),
                      ACTIVITYEND TIMESTAMP(6),
                      ACTIVITY CLOB
                  )
                  */
      }
  }
  </code></pre>
  
  <p>I want to use this Oracle table to store data: </p>
  
  <pre><code>-- TABLE ACTIVESESSIONSLOG
  
  CREATE TABLE ACTIVESESSIONSLOG(
    ASESSIONID VARCHAR2(30 ) NOT NULL,
    USERID VARCHAR2(30 ),
    ACTIVITYSTART TIMESTAMP(6),
    ACTIVITYEND TIMESTAMP(6),
    ACTIVITY CLOB
  )
  /
  </code></pre>
  
  <p>There are some problems that I cannot fix:
  1. I want to use pure JSF without the Tomahawk component library itself which under each contains the t:dataList and t:saveState components
  2. I want to use the java code for the Oracle table and I want to simplify the code - remove the code that is not needed.</p>
  
  <p>I will give all my Reputation points in a bounty to the one who will help me to fix the code when bounty is available (after two days) no mater when the code is fixed now or later. </p>
  
  <p>Best wishes 
  Peter </p>