[New] Rewrote the Paging class to use offset/limit

Also returns next, previous and last offsets. Added helper method to
create a REST Response from a page in ResponseUtil
This commit is contained in:
Robert von Burg 2016-10-07 11:55:08 +02:00
parent ba476b2f68
commit 992f3966dc
6 changed files with 266 additions and 101 deletions

View File

@ -22,4 +22,14 @@ public class StrolchRestfulConstants {
public static final String STROLCH_CERTIFICATE = "strolch.certificate"; //$NON-NLS-1$
public static final String STROLCH_AUTHORIZATION = "strolch.authorization"; //$NON-NLS-1$
public static final String MSG = "msg";
public static final String DATA = "data";
public static final String LAST_OFFSET = "lastOffset";
public static final String NEXT_OFFSET = "nextOffset";
public static final String PREVIOUS_OFFSET = "previousOffset";
public static final String SIZE = "size";
public static final String OFFSET = "offset";
public static final String LIMIT = "limit";
}

View File

@ -225,23 +225,25 @@ public class ModelQuery {
StrolchElementVisitor<T, JsonObject> toJsonVisitor) {
// paging
Paging<T> paging = Paging.asPage(elements, queryData.getPageSize(), queryData.getPage());
Paging<T> paging = Paging.asPage(elements, queryData.getOffset(), queryData.getLimit());
// get page
List<T> page = paging.getPage();
JsonObject root = new JsonObject();
root.addProperty("msg", "-");
root.addProperty("draw", queryData.getDraw());
root.addProperty("limit", paging.getLimit());
root.addProperty("offset", paging.getOffset());
root.addProperty("size", paging.getSize());
root.addProperty("previousOffset", paging.getPreviousOffset());
root.addProperty("nextOffset", paging.getNextOffset());
root.addProperty("lastOffset", paging.getLastOffset());
root.addProperty("dataSetSize", dataSetSize);
root.addProperty("nrOfElements", paging.getNrOfElements());
if (StringHelper.isNotEmpty(queryData.getOrderBy()))
root.addProperty("sortBy", queryData.getOrderBy());
root.addProperty("ascending", queryData.isAscending());
root.addProperty("nrOfPages", paging.getNrOfPages());
root.addProperty("pageSize", paging.getPageSize());
root.addProperty("page", paging.getPageToReturn());
// add items
JsonArray data = new JsonArray();

View File

@ -7,14 +7,11 @@ public class QueryData {
@QueryParam("realmName")
private String realmName;
@QueryParam("draw")
private int draw;
@QueryParam("offset")
private int offset;
@QueryParam("pageSize")
private int pageSize;
@QueryParam("page")
private int page;
@QueryParam("limit")
private int limit;
@QueryParam("query")
private String query;
@ -33,14 +30,6 @@ public class QueryData {
this.realmName = realmName;
}
public int getDraw() {
return this.draw;
}
public void setDraw(int draw) {
this.draw = draw;
}
public String getOrderBy() {
return this.orderBy;
}
@ -57,20 +46,20 @@ public class QueryData {
this.ascending = ascending;
}
public int getPageSize() {
return this.pageSize;
public int getOffset() {
return this.offset;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
public void setOffset(int offset) {
this.offset = offset;
}
public int getPage() {
return this.page;
public int getLimit() {
return this.limit;
}
public void setPage(int page) {
this.page = page;
public void setLimit(int limit) {
this.limit = limit;
}
public String getQuery() {

View File

@ -1,12 +1,25 @@
package li.strolch.rest.helper;
import static li.strolch.rest.StrolchRestfulConstants.DATA;
import static li.strolch.rest.StrolchRestfulConstants.LAST_OFFSET;
import static li.strolch.rest.StrolchRestfulConstants.LIMIT;
import static li.strolch.rest.StrolchRestfulConstants.MSG;
import static li.strolch.rest.StrolchRestfulConstants.NEXT_OFFSET;
import static li.strolch.rest.StrolchRestfulConstants.OFFSET;
import static li.strolch.rest.StrolchRestfulConstants.PREVIOUS_OFFSET;
import static li.strolch.rest.StrolchRestfulConstants.SIZE;
import java.util.List;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import li.strolch.utils.collections.Paging;
import li.strolch.utils.helper.ExceptionHelper;
import li.strolch.utils.helper.StringHelper;
@ -15,8 +28,6 @@ import li.strolch.utils.helper.StringHelper;
*/
public class ResponseUtil {
public static final String MSG = "msg";
public static Response toResponse() {
JsonObject response = new JsonObject();
response.addProperty(MSG, StringHelper.DASH);
@ -64,4 +75,30 @@ public class ResponseUtil {
return Response.serverError().entity(json).type(MediaType.APPLICATION_JSON).build();
}
public static Response toResponse(Paging<JsonObject> paging) {
JsonObject response = new JsonObject();
response.addProperty(MSG, StringHelper.DASH);
response.addProperty(LIMIT, paging.getLimit());
response.addProperty(OFFSET, paging.getOffset());
response.addProperty(SIZE, paging.getSize());
response.addProperty(PREVIOUS_OFFSET, paging.getPreviousOffset());
response.addProperty(NEXT_OFFSET, paging.getNextOffset());
response.addProperty(LAST_OFFSET, paging.getLastOffset());
List<JsonObject> page = paging.getPage();
JsonArray data = new JsonArray();
for (JsonObject jsonObject : page) {
JsonObject element = jsonObject;
data.add(element);
}
response.add(DATA, data);
String json = new Gson().toJson(response);
return Response.ok(json, MediaType.APPLICATION_JSON).build();
}
}

View File

@ -18,6 +18,9 @@ package li.strolch.utils.collections;
import java.util.List;
/**
* Paging helper creating windows on result list of queries. The input is the original complete list, and with the help
* of an offset and a limit, a page/window can be fetched.
*
* @author Robert von Burg &lt;eitch@eitchnet.ch&gt;
*
* @param <T>
@ -25,108 +28,138 @@ import java.util.List;
*/
public class Paging<T> {
private int pageSize;
private int pageToReturn;
private int nrOfPages;
private int nrOfElements;
private int limit;
private int offset;
private int size;
private List<T> input;
private List<T> page;
private Paging(int pageSize, int indexOfPageToReturn) {
this.pageSize = pageSize;
this.pageToReturn = indexOfPageToReturn;
private int nextOffset;
private int previousOffset;
private int firstOffset;
private int lastOffset;
private Paging() {
// empty constructor
}
public int getPageSize() {
return this.pageSize;
/**
* @return the max number of elements to be returned in the page/window
*/
public int getLimit() {
return this.limit;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
/**
* @return the offset in the input list for the page/window
*/
public int getOffset() {
return this.offset;
}
public int getPageToReturn() {
return this.pageToReturn;
/**
* @return the next offset, i.e. offset + limit
*/
public int getNextOffset() {
return this.nextOffset;
}
public void setPageToReturn(int pageToReturn) {
this.pageToReturn = pageToReturn;
/**
* @return the previous offset, i.e. offset - limit
*/
public int getPreviousOffset() {
return this.previousOffset;
}
public int getNrOfPages() {
return this.nrOfPages;
/**
* @return 0, as the first offset is the first element in the input list
*/
public int getFirstOffset() {
return this.firstOffset;
}
public void setNrOfPages(int nrOfPages) {
this.nrOfPages = nrOfPages;
/**
* @return the last possible offset given the offset, limit and input size
*/
public int getLastOffset() {
return this.lastOffset;
}
public int getNrOfElements() {
return this.nrOfElements;
}
public void setNrOfElements(int nrOfElements) {
this.nrOfElements = nrOfElements;
/**
* @return the size of the input list
*/
public int getSize() {
return this.size;
}
/**
* @return the input
*/
public List<T> getInput() {
return this.input;
}
/**
* @return the current page/window
*/
public List<T> getPage() {
return this.page;
}
/**
* Creates a sub list of the given list by creating defining start and end from the requested page of the form
* Creates a sub list of the input list with the given limit and offset
*
* @param list
* the list to paginate
* @param pageSize
* The number of items to return in each page
* @param page
* the page to return - start index is 1
*
* the list to paginate / create a window for
* @param offset
* where to start the sub list
* @param limit
* The number of items to return in each page/window
* @return a {@link Paging} instance from which the selected page (list) can be retrieved
*
* @param <T>
* the type of element in the list
*/
public static <T> Paging<T> asPage(List<T> list, int pageSize, int page) {
public static <T> Paging<T> asPage(List<T> list, int offset, int limit) {
Paging<T> paging = new Paging<>(pageSize, page);
paging.nrOfElements = list.size();
Paging<T> paging = new Paging<>();
paging.firstOffset = 0;
paging.limit = limit;
paging.offset = offset;
paging.size = list.size();
paging.input = list;
paging.firstOffset = 0;
if (paging.limit <= 0 || paging.offset < 0) {
paging.offset = 0;
paging.limit = list.size();
if (paging.pageSize <= 0 || paging.pageToReturn <= 0) {
paging.nrOfPages = 0;
paging.pageSize = list.size();
paging.pageToReturn = 0;
paging.input = list;
paging.page = list;
paging.nextOffset = 0;
paging.lastOffset = 0;
paging.previousOffset = 0;
return paging;
}
int size = list.size();
paging.page = list.subList(offset, Math.min(paging.size, offset + limit));
// calculate maximum number of pages
paging.nrOfPages = size / paging.pageSize;
if (size % paging.pageSize != 0)
paging.nrOfPages++;
if (limit == 1) {
// and from this validate requested page
paging.pageToReturn = Math.min(paging.pageToReturn, paging.nrOfPages);
paging.nextOffset = Math.min(paging.size - 1, offset + 1);
paging.previousOffset = Math.max(0, offset - 1);
paging.lastOffset = paging.size - 1;
// now we can calculate the start and end of the page
int start = Math.max(0, paging.pageSize * paging.pageToReturn - paging.pageSize);
int end = Math.min(size, paging.pageSize * paging.pageToReturn);
} else {
// and return the list
paging.page = list.subList(start, end);
// fix page size
if (paging.page.size() < paging.pageSize)
paging.pageSize = paging.page.size();
paging.nextOffset = Math.min(paging.size - 1, limit + offset);
paging.previousOffset = Math.max(0, offset - limit);
paging.lastOffset = offset + ((paging.size - offset) - ((paging.size - offset) % limit));
}
return paging;
}

View File

@ -22,59 +22,153 @@ import java.util.List;
import org.junit.Test;
import li.strolch.utils.collections.Paging;
/**
* @author Robert von Burg &lt;eitch@eitchnet.ch&gt;
*/
public class PagingTest {
private List<String> getInputList() {
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f", "g");
return list;
}
@Test
public void shouldReturnAll() {
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f");
List<String> list = getInputList();
List<String> page = Paging.asPage(list, -1, -1).getPage();
assertEquals(list, page);
page = Paging.asPage(list, 0, 0).getPage();
assertEquals(list, page);
}
@Test
public void shouldReturnFirstPage1() {
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f");
List<String> page = Paging.asPage(list, 1, 1).getPage();
List<String> list = getInputList();
List<String> page = Paging.asPage(list, 0, 1).getPage();
assertEquals(Arrays.asList("a"), page);
}
@Test
public void shouldReturnFirstPage2() {
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f");
List<String> page = Paging.asPage(list, 2, 1).getPage();
List<String> list = getInputList();
List<String> page = Paging.asPage(list, 0, 2).getPage();
assertEquals(Arrays.asList("a", "b"), page);
}
@Test
public void shouldReturnSecondPage1() {
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f");
List<String> page = Paging.asPage(list, 1, 2).getPage();
List<String> list = getInputList();
List<String> page = Paging.asPage(list, 1, 1).getPage();
assertEquals(Arrays.asList("b"), page);
}
@Test
public void shouldReturnSecondPage2() {
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f");
List<String> list = getInputList();
List<String> page = Paging.asPage(list, 2, 2).getPage();
assertEquals(Arrays.asList("c", "d"), page);
}
@Test
public void shouldReturnLastPage1() {
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f");
List<String> page = Paging.asPage(list, 1, 6).getPage();
List<String> list = getInputList();
List<String> page = Paging.asPage(list, 5, 1).getPage();
assertEquals(Arrays.asList("f"), page);
}
@Test
public void shouldReturnLastPage2() {
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f");
List<String> page = Paging.asPage(list, 2, 3).getPage();
List<String> list = getInputList();
List<String> page = Paging.asPage(list, 4, 2).getPage();
assertEquals(Arrays.asList("e", "f"), page);
}
@Test
public void shouldReturnLastPage3() {
List<String> list = getInputList();
Paging<String> paging = Paging.asPage(list, 0, 2);
List<String> page = paging.getPage();
assertEquals(Arrays.asList("a", "b"), page);
assertEquals(0, paging.getFirstOffset());
assertEquals(2, paging.getNextOffset());
assertEquals(6, paging.getLastOffset());
paging = Paging.asPage(list, paging.getLastOffset(), 2);
page = paging.getPage();
assertEquals(Arrays.asList("g"), page);
assertEquals(0, paging.getFirstOffset());
assertEquals(6, paging.getNextOffset());
assertEquals(6, paging.getLastOffset());
}
@Test
public void shouldReturnLastPage4() {
List<String> list = getInputList();
Paging<String> paging = Paging.asPage(list, 0, 1);
List<String> page = paging.getPage();
assertEquals(Arrays.asList("a"), page);
paging = Paging.asPage(list, paging.getLastOffset(), 1);
page = paging.getPage();
assertEquals(Arrays.asList("g"), page);
assertEquals(0, paging.getFirstOffset());
assertEquals(6, paging.getNextOffset());
assertEquals(6, paging.getLastOffset());
}
@Test
public void shouldReturnLastPage5() {
List<String> list = getInputList();
Paging<String> paging = Paging.asPage(list, 0, 3);
List<String> page = paging.getPage();
assertEquals(Arrays.asList("a", "b", "c"), page);
assertEquals(0, paging.getFirstOffset());
assertEquals(3, paging.getNextOffset());
assertEquals(6, paging.getLastOffset());
page = Paging.asPage(list, paging.getNextOffset(), paging.getLimit()).getPage();
assertEquals(Arrays.asList("d", "e", "f"), page);
page = Paging.asPage(list, paging.getLastOffset(), paging.getLimit()).getPage();
assertEquals(Arrays.asList("g"), page);
}
@Test
public void shouldReturnLastPage6() {
List<String> list = getInputList();
Paging<String> paging = Paging.asPage(list, 1, 1);
List<String> page = paging.getPage();
assertEquals(Arrays.asList("b"), page);
page = Paging.asPage(list, paging.getPreviousOffset(), paging.getLimit()).getPage();
assertEquals(Arrays.asList("a"), page);
page = Paging.asPage(list, paging.getNextOffset(), paging.getLimit()).getPage();
assertEquals(Arrays.asList("c"), page);
page = Paging.asPage(list, paging.getLastOffset(), paging.getLimit()).getPage();
assertEquals(Arrays.asList("g"), page);
}
@Test
public void shouldReturnLastPage7() {
List<String> list = getInputList();
Paging<String> paging = Paging.asPage(list, 2, 2);
List<String> page = paging.getPage();
assertEquals(Arrays.asList("c", "d"), page);
page = Paging.asPage(list, paging.getPreviousOffset(), paging.getLimit()).getPage();
assertEquals(Arrays.asList("a", "b"), page);
page = Paging.asPage(list, paging.getNextOffset(), paging.getLimit()).getPage();
assertEquals(Arrays.asList("e", "f"), page);
page = Paging.asPage(list, paging.getLastOffset(), paging.getLimit()).getPage();
assertEquals(Arrays.asList("g"), page);
}
}