// ===================================================================================
  //                                                        isNecessaryToReadPageAgain()
  //                                                        ============================
  public void test_isNecessaryToReadPageAgain() {
    // ## Arrange ##
    List<String> selectedList = new ArrayList<String>();
    PagingResultBean<String> rb = new PagingResultBean<String>();
    rb.setSelectedList(selectedList);
    PagingInvoker<String> tgt = createTarget();

    // ## Act & Assert ##
    rb.setAllRecordCount(0);
    assertFalse(tgt.isNecessaryToReadPageAgain(rb));
    rb.setAllRecordCount(1);
    assertTrue(tgt.isNecessaryToReadPageAgain(rb));
    selectedList.add("one");
    assertFalse(tgt.isNecessaryToReadPageAgain(rb));
    rb.setAllRecordCount(0);
    assertFalse(tgt.isNecessaryToReadPageAgain(rb));
  }
  public void test_invokePaging_threePageCurrent_countLater_just() {
    // ## Arrange ##
    final List<String> selectedList = new ArrayList<String>();
    fillList(selectedList, 20);
    final SimplePagingBean pagingBean =
        new SimplePagingBean() {
          @Override
          public boolean canPagingCountLater() {
            return true;
          }
        };
    pagingBean.getSqlClause().registerOrderBy("aaa", true, new MockColumnInfo());
    pagingBean.fetchFirst(20);
    pagingBean.fetchPage(3);
    PagingInvoker<String> tgt = createTarget();

    // ## Act ##
    final List<String> markList = new ArrayList<String>();
    PagingResultBean<String> rb =
        tgt.invokePaging(
            new PagingHandler<String>() {
              public PagingBean getPagingBean() {
                return pagingBean;
              }

              public int count() {
                markList.add("count");
                return 60;
              }

              public List<String> paging() {
                markList.add("paging");
                return selectedList;
              }
            });

    // ## Assert ##
    assertEquals(20, rb.size());
    assertEquals(60, rb.getAllRecordCount());
    assertEquals(3, rb.getAllPageCount());
    assertEquals(1, rb.getOrderByClause().getOrderByList().size());
    assertEquals("paging", markList.get(0));
    assertEquals("count", markList.get(1));
  }
  // ===================================================================================
  //                                                                      invokePaging()
  //                                                                      ==============
  public void test_invokePaging_emtpy() {
    // ## Arrange ##
    final List<String> selectedList = new ArrayList<String>();
    final SimplePagingBean pagingBean = new SimplePagingBean();
    pagingBean.getSqlClause().registerOrderBy("aaa", true, new MockColumnInfo());
    pagingBean.fetchFirst(20);
    PagingInvoker<String> tgt = createTarget();

    // ## Act ##
    final List<String> markList = new ArrayList<String>();
    PagingResultBean<String> rb =
        tgt.invokePaging(
            new PagingHandler<String>() {
              public PagingBean getPagingBean() {
                return pagingBean;
              }

              public int count() {
                markList.add("count");
                return 0;
              }

              public List<String> paging() {
                markList.add("paging");
                return selectedList;
              }
            });

    // ## Assert ##
    assertEquals(0, rb.size());
    assertEquals(0, rb.getAllRecordCount());
    assertEquals(1, rb.getAllPageCount());
    assertEquals(1, rb.getOrderByClause().getOrderByList().size());
    assertEquals("count", markList.get(0));
    assertEquals(1, markList.size());
  }
  /**
   * 依設定執行多階段分頁
   *
   * @param <T> 回傳的 List Generic Type
   * @param filter 實作取得資料的 Closure
   * @param resultBean 分頁的資料物件
   * @param fetchPhase 要執行的階段
   * @return 可能為 Empty List 的結果
   * @see #runTwoPhasePagingFilter(TwoPhasePagingFilter, PagingResultBean)
   */
  public static <T> List<T> runTwoPhasePagingFilter(
      TwoPhasePagingFilter<T> filter, PagingResultBean resultBean, FetchPhase fetchPhase) {
    checkValidPagingResultBean(resultBean);
    fetchPhase = processFetchPhase(fetchPhase);

    /** 要求最後一頁,直接查詢全部資料,有以下特性 1. 最後一筆往前取得每頁筆數為所在資料 2. 請求後 N 頁一律為 0 3. 不會進行第二次查詢 */
    PagingRequestBean pagingRequestBean = resultBean.getPagingRequestBean();
    if (pagingRequestBean.getPageNumberOfTarget() == PagingRequestBean.LAST_PAGE) {
      List<T> resultData = filter.lastPhasePaging(resultBean);
      resultBean.setResultSize(resultData.size(), FetchPhase.LastFetch);

      return FetchPhase.LastFetch.filterToPage(resultData, pagingRequestBean.getPageSize());
    }
    // :~)

    /** 兩階段查詢 */
    // ==================================================
    /** 第一次查詢 */
    List<T> resultData = filter.firstPhasePaging(resultBean);
    resultBean.setResultSize(resultData.size());
    // :~)

    /** 判斷是否要執行第二次查詢,需滿足以下條件 1. 第一階段沒有任何資料 2. 設定為二階段查詢 3. 請求的分頁大於 1 */
    if (resultBean.getResultStatus() == ResultStatus.EmptyData
        && fetchPhase == FetchPhase.LastFetch
        && pagingRequestBean.hasPreviousPage()) {
      /** 第二階段查詢以「最後一頁」為查詢策略 */
      pagingRequestBean.setPageNumberOfTarget(PagingRequestBean.LAST_PAGE);
      resultBean.setPagingRequestBean(pagingRequestBean);
      // :~)

      return runTwoPhasePagingFilter(filter, resultBean); // 遞迴呼叫請求「最後一頁」
    }
    // :~)

    return FetchPhase.FirstFetch.filterToPage(
        resultData, resultBean.getPagingRequestBean().getPageSize());
    // ================================================== :~)
  }
 private static void checkValidPagingResultBean(PagingResultBean pagingResultBean) {
   notNull(pagingResultBean, "Paging result bean is null");
   notNull(pagingResultBean.getPagingRequestBean(), "Request paging data is null");
 }