View Javadoc
1   package org.nuiton.util.pagination;
2   
3   /*
4    * #%L
5    * Nuiton Utils
6    * %%
7    * Copyright (C) 2004 - 2017 CodeLutin
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * #L%
23   */
24  
25  import com.google.common.base.Preconditions;
26  
27  import java.io.Serializable;
28  import java.util.LinkedList;
29  import java.util.List;
30  import java.util.function.Function;
31  import java.util.stream.Collectors;
32  
33  /**
34   * Represents the result of a pagination request. It contains the result elements together with the
35   * {@link PaginationParameter} used to compute it. The class also contains methods to
36   * navigate through the other pages.
37   *
38   * @author Arnaud Thimel (Code Lutin)
39   * @since 3.0
40   */
41  public class PaginationResult<O> implements Serializable {
42  
43      private static final long serialVersionUID = 1L;
44  
45      protected List<O> elements;
46      protected long count;
47      protected PaginationParameter currentPage;
48  
49      protected PaginationResult(List<O> elements, long count, PaginationParameter currentPage) {
50          this.elements = elements;
51          this.count = count;
52          this.currentPage = currentPage;
53      }
54  
55      /**
56       * Creates an instance using the already computed list of {code}elements{/code} and {code}count{/count}, together
57       * with the {code}currentPage{/code} {@link PaginationParameter} used to build it.
58       *
59       * @param elements    the list of elements
60       * @param count       the total number of elements (through all pages)
61       * @param currentPage the PaginationParameter used to build this paged result
62       * @param <T>         any object type
63       * @return the built instance of PaginationResult
64       */
65      public static <T> PaginationResult<T> of(List<T> elements, long count, PaginationParameter currentPage) {
66          PaginationResult<T> result = new PaginationResult<T>(elements, count, currentPage);
67          return result;
68      }
69  
70      /**
71       * Creates an instance using the full list of elements ({code}fullList{/code}) and the {code}requestedPage{/code}
72       * {@link PaginationParameter}. The built instance of PaginationResult will contain a sub list of the given
73       * {code}fullList{/code} parameter.
74       *
75       * @param fullList      the full list of elements
76       * @param requestedPage the PaginationParameter to use to build this paged result
77       * @param <T>           any object type
78       * @return the built instance of PaginationResult.
79       */
80      public static <T> PaginationResult<T> fromFullList(List<T> fullList, PaginationParameter requestedPage) {
81  
82          List<T> subList;
83  
84          int startIndex = requestedPage.getStartIndex();
85  
86          if (requestedPage.isAll()) {
87              // Full list requested, use the full list
88              subList = fullList;
89          } else if (startIndex >= fullList.size()) {
90              // If requested page is out of range, return an empty list
91              subList = new LinkedList<T>();
92          } else {
93              int toIndex = Math.min(requestedPage.getEndIndex() + 1, fullList.size());
94              subList = fullList.subList(startIndex, toIndex);
95          }
96  
97          PaginationResult<T> result = PaginationResult.of(subList, fullList.size(), requestedPage);
98          return result;
99      }
100 
101     public List<O> getElements() {
102         return elements;
103     }
104 
105     public long getCount() {
106         return count;
107     }
108 
109     public PaginationParameter getCurrentPage() {
110         return currentPage;
111     }
112 
113     public PaginationParameter getNextPage() {
114         int nextPageNumber = currentPage.getPageNumber() + 1;
115         int pageSize = currentPage.getPageSize();
116         List<PaginationOrder> orderClauses = currentPage.getOrderClauses();
117         PaginationParameter result = PaginationParameter.
118                 builder(nextPageNumber, pageSize).
119                 addOrderClauses(orderClauses).
120                 build();
121         return result;
122     }
123 
124     public PaginationParameter getPreviousPage() {
125         // XXX AThimel 21/05/14 Maybe, do not fail, just return the first page ?
126         Preconditions.checkState(hasPreviousPage(), "You cannot get a previous page to the first one");
127         int previousPageNumber = currentPage.getPageNumber() - 1;
128         int pageSize = currentPage.getPageSize();
129         List<PaginationOrder> orderClauses = currentPage.getOrderClauses();
130         PaginationParameter result = PaginationParameter.
131                 builder(previousPageNumber, pageSize).
132                 addOrderClauses(orderClauses).
133                 build();
134         return result;
135     }
136 
137     public PaginationParameter getFirstPage() {
138         int firstPageNumber = 0;
139         int pageSize = currentPage.getPageSize();
140         List<PaginationOrder> orderClauses = currentPage.getOrderClauses();
141         PaginationParameter result = PaginationParameter.
142                 builder(firstPageNumber, pageSize).
143                 addOrderClauses(orderClauses).
144                 build();
145         return result;
146     }
147 
148     public PaginationParameter getLastPage() {
149         // AThimel 28/05/14 Math.max(0, ...) to make sure last page is working even if there is no result
150         int lastPageNumber = Math.max(0, getPageCount() - 1);
151         int pageSize = currentPage.getPageSize();
152         List<PaginationOrder> orderClauses = currentPage.getOrderClauses();
153         PaginationParameter result = PaginationParameter.
154                 builder(lastPageNumber, pageSize).
155                 addOrderClauses(orderClauses).
156                 build();
157         return result;
158     }
159 
160     public int getPageCount() {
161         int pageCount = 1;
162         int pageSize = currentPage.getPageSize();
163         if (pageSize >= 1) {
164             double countDouble = Long.valueOf(count).doubleValue();
165             double pageSizeDouble = Integer.valueOf(pageSize).doubleValue();
166             double pageNumberDouble = Math.ceil(countDouble / pageSizeDouble);
167             pageCount = Double.valueOf(pageNumberDouble).intValue();
168         }
169         return pageCount;
170     }
171 
172     public boolean hasNextPage() {
173         int lastPageNumber = getPageCount() - 1;
174         boolean result = currentPage.getPageNumber() < lastPageNumber;
175         return result;
176     }
177 
178     public boolean hasPreviousPage() {
179         boolean result = currentPage.getPageNumber() > 0;
180         return result;
181     }
182 
183     /**
184      * Creates an instance of PaginationResult transforming the current one using the given function
185      */
186     public <T> PaginationResult<T> transform(Function<? super O, ? extends T> function) {
187         List<T> transformedElements = getElements().stream()
188                 .map(function)
189                 .collect(Collectors.toList());
190         PaginationResult<T> result = PaginationResult.of(transformedElements, getCount(), getCurrentPage());
191         return result;
192     }
193 
194 }