[Major] Inspector now has offset/limit for queries

This commit is contained in:
Robert von Burg 2017-02-08 20:16:05 +01:00
parent b70106260a
commit 0e5176df62
7 changed files with 252 additions and 190 deletions

View File

@ -23,6 +23,7 @@ import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.BeanParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
@ -37,6 +38,8 @@ import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
@ -53,6 +56,11 @@ import li.strolch.model.activity.Activity;
import li.strolch.model.json.ActivityToJsonVisitor;
import li.strolch.model.json.OrderToJsonVisitor;
import li.strolch.model.json.ResourceToJsonVisitor;
import li.strolch.model.query.ActivityQuery;
import li.strolch.model.query.OrderQuery;
import li.strolch.model.query.ResourceQuery;
import li.strolch.model.query.StrolchTypeNavigation;
import li.strolch.model.query.parser.QueryParser;
import li.strolch.model.xml.ActivityToXmlStringVisitor;
import li.strolch.model.xml.OrderToXmlStringVisitor;
import li.strolch.model.xml.ResourceToXmlStringVisitor;
@ -63,6 +71,7 @@ import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.model.Certificate;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.StrolchRestfulConstants;
import li.strolch.rest.helper.RestfulHelper;
import li.strolch.rest.model.Result;
import li.strolch.service.UpdateActivityService;
import li.strolch.service.UpdateActivityService.UpdateActivityArg;
@ -71,7 +80,6 @@ import li.strolch.service.UpdateOrderService.UpdateOrderArg;
import li.strolch.service.UpdateResourceService;
import li.strolch.service.UpdateResourceService.UpdateResourceArg;
import li.strolch.service.api.ServiceResult;
import li.strolch.utils.iso8601.ISO8601FormatFactory;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
@ -352,41 +360,46 @@ public class Inspector {
* @param realm
* the realm for which the resource type overview is to be returned
* @param type
*
* marshall
* @return an overview of the {@link Resource Resources} with the given type. This is a list of overviews of the
* resources
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/resources/{type}")
public Response getResourceTypeDetails(@PathParam("realm") String realm, @PathParam("type") String type,
@Context HttpServletRequest request) {
public Response queryResourcesByType(@BeanParam QueryData queryData, @PathParam("realm") String realm,
@PathParam("type") String type, @Context HttpServletRequest request) {
queryData.initializeUnsetFields();
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
JsonObject typeDetailJ = new JsonObject();
typeDetailJ.addProperty(Tags.Json.OBJECT_TYPE, Tags.Json.RESOURCE);
typeDetailJ.addProperty(Tags.Json.TYPE, type);
List<Resource> resources = new ArrayList<>();
JsonArray elementsJ = new JsonArray();
typeDetailJ.add(Tags.Json.ELEMENTS, elementsJ);
// parse the query string
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery(queryData.getQuery(), true, true);
// set navigation to requested type
query.setNavigation(new StrolchTypeNavigation(type));
// query the data
long dataSetSize = 0L;
try (StrolchTransaction tx = openTx(cert, realm)) {
List<Resource> byType = tx.getResourceMap().getElementsBy(tx, type);
for (Resource resource : byType) {
JsonObject elementJ = new JsonObject();
elementJ.addProperty(Tags.Json.OBJECT_TYPE, Tags.RESOURCE);
elementJ.addProperty(Tags.Json.ID, resource.getId());
elementJ.addProperty(Tags.Json.NAME, resource.getName());
elementJ.addProperty(Tags.Json.TYPE, resource.getType());
elementsJ.add(elementJ);
}
ResourceMap resourceMap = tx.getResourceMap();
dataSetSize = resourceMap.querySize(tx);
resources.addAll(tx.doQuery(query));
}
return Response.ok().entity(typeDetailJ.toString()).build();
// do ordering
RestfulHelper.doOrdering(queryData, resources);
// build JSON response
ResourceToJsonVisitor toJsonVisitor = new ResourceToJsonVisitor();
JsonObject root = RestfulHelper.toJson(queryData, dataSetSize, resources, toJsonVisitor);
// marshall result
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String entity = gson.toJson(root);
return Response.ok(entity).build();
}
/**
@ -406,71 +419,73 @@ public class Inspector {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/orders/{type}")
public Response getOrderTypeDetails(@PathParam("realm") String realm, @PathParam("type") String type,
@Context HttpServletRequest request) {
public Response queryOrdersByType(@BeanParam QueryData queryData, @PathParam("realm") String realm,
@PathParam("type") String type, @Context HttpServletRequest request) {
queryData.initializeUnsetFields();
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
JsonObject typeDetailJ = new JsonObject();
typeDetailJ.addProperty(Tags.Json.OBJECT_TYPE, Tags.Json.ORDER);
typeDetailJ.addProperty(Tags.Json.TYPE, type);
List<Order> orders = new ArrayList<>();
JsonArray elementsJ = new JsonArray();
typeDetailJ.add(Tags.Json.ELEMENTS, elementsJ);
// parse the query string
OrderQuery<Order> query = QueryParser.parseToOrderQuery(queryData.getQuery(), true, true);
query.setNavigation(new StrolchTypeNavigation(type));
try (StrolchTransaction tx = openTx(cert, realm)) {
List<Order> byType = tx.getOrderMap().getElementsBy(tx, type);
for (Order order : byType) {
JsonObject elementJ = new JsonObject();
elementJ.addProperty(Tags.Json.OBJECT_TYPE, Tags.ORDER);
elementJ.addProperty(Tags.Json.ID, order.getId());
elementJ.addProperty(Tags.Json.NAME, order.getName());
elementJ.addProperty(Tags.Json.TYPE, order.getType());
elementJ.addProperty(Tags.Json.STATE, order.getState().getName());
elementJ.addProperty(Tags.Json.DATE, ISO8601FormatFactory.getInstance().formatDate(order.getDate()));
elementsJ.add(elementJ);
}
// query the data
long dataSetSize = 0L;
try (StrolchTransaction tx = openTx(cert, queryData.getRealmName())) {
OrderMap orderMap = tx.getOrderMap();
dataSetSize = orderMap.querySize(tx);
orders.addAll(tx.doQuery(query));
}
return Response.ok().entity(typeDetailJ.toString()).build();
// do ordering
RestfulHelper.doOrdering(queryData, orders);
// build JSON response
OrderToJsonVisitor toJsonVisitor = new OrderToJsonVisitor();
JsonObject root = RestfulHelper.toJson(queryData, dataSetSize, orders, toJsonVisitor);
// marshall result
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String entity = gson.toJson(root);
return Response.ok(entity).build();
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{realm}/activities/{type}")
public Response getActivities(@PathParam("realm") String realm, @PathParam("type") String type,
@Context HttpServletRequest request) {
public Response queryActivitiesByType(@BeanParam QueryData queryData, @PathParam("realm") String realm,
@PathParam("type") String type, @Context HttpServletRequest request) {
queryData.initializeUnsetFields();
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
JsonObject typeDetailJ = new JsonObject();
typeDetailJ.addProperty(Tags.Json.OBJECT_TYPE, Tags.Json.ACTIVITY);
typeDetailJ.addProperty(Tags.Json.TYPE, type);
List<Activity> activities = new ArrayList<>();
JsonArray elementsJ = new JsonArray();
typeDetailJ.add(Tags.Json.ELEMENTS, elementsJ);
// parse the query string
ActivityQuery<Activity> query = QueryParser.parseToActivityQuery(queryData.getQuery(), true, true);
query.setNavigation(new StrolchTypeNavigation(type));
try (StrolchTransaction tx = openTx(cert, realm)) {
List<Activity> byType = tx.getActivityMap().getElementsBy(tx, type);
for (Activity activity : byType) {
JsonObject elementJ = new JsonObject();
elementJ.addProperty(Tags.Json.OBJECT_TYPE, Tags.ACTIVITY);
elementJ.addProperty(Tags.Json.ID, activity.getId());
elementJ.addProperty(Tags.Json.NAME, activity.getName());
elementJ.addProperty(Tags.Json.TYPE, activity.getType());
elementJ.addProperty(Tags.Json.STATE, activity.getState().getName());
elementJ.addProperty(Tags.Json.TIME_ORDERING, activity.getTimeOrdering().getName());
elementsJ.add(elementJ);
}
// query the data
long dataSetSize = 0L;
try (StrolchTransaction tx = openTx(cert, queryData.getRealmName())) {
ActivityMap activityMap = tx.getActivityMap();
dataSetSize = activityMap.querySize(tx);
activities.addAll(tx.doQuery(query));
}
return Response.ok().entity(typeDetailJ.toString()).build();
// do ordering
RestfulHelper.doOrdering(queryData, activities);
// build JSON response
ActivityToJsonVisitor toJsonVisitor = new ActivityToJsonVisitor();
JsonObject root = RestfulHelper.toJson(queryData, dataSetSize, activities, toJsonVisitor);
// marshall result
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String entity = gson.toJson(root);
return Response.ok(entity).build();
}
@GET

View File

@ -13,12 +13,8 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import li.strolch.agent.api.ActivityMap;
@ -26,8 +22,6 @@ import li.strolch.agent.api.OrderMap;
import li.strolch.agent.api.ResourceMap;
import li.strolch.model.Order;
import li.strolch.model.Resource;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.Tags;
import li.strolch.model.activity.Activity;
import li.strolch.model.json.ActivityToJsonVisitor;
import li.strolch.model.json.OrderToJsonVisitor;
@ -37,20 +31,15 @@ import li.strolch.model.query.OrderQuery;
import li.strolch.model.query.ResourceQuery;
import li.strolch.model.query.StrolchTypeNavigation;
import li.strolch.model.query.parser.QueryParser;
import li.strolch.model.visitor.StrolchElementVisitor;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.model.Certificate;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.StrolchRestfulConstants;
import li.strolch.runtime.StrolchConstants;
import li.strolch.utils.collections.Paging;
import li.strolch.utils.helper.StringHelper;
import li.strolch.rest.helper.RestfulHelper;
@Path("strolch/model")
public class ModelQuery {
private static final Logger logger = LoggerFactory.getLogger(ModelQuery.class);
/**
* Query {@link Resource Resources} by parsing the query string in {@link QueryData#getQuery()} using
* {@link QueryParser}
@ -66,10 +55,9 @@ public class ModelQuery {
@Produces(MediaType.APPLICATION_JSON)
@Path("resources")
public Response queryResources(@BeanParam QueryData queryData, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// see if a special realm was requested
String realmName = getRealmName(queryData);
queryData.initializeUnsetFields();
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
List<Resource> resources = new ArrayList<>();
@ -78,7 +66,7 @@ public class ModelQuery {
// query the data
long dataSetSize = 0L;
try (StrolchTransaction tx = openTx(cert, realmName)) {
try (StrolchTransaction tx = openTx(cert, queryData.getRealmName())) {
ResourceMap resourceMap = tx.getResourceMap();
if (query.hasNavigation()) {
@ -96,11 +84,11 @@ public class ModelQuery {
}
// do ordering
doOrdering(queryData, resources);
RestfulHelper.doOrdering(queryData, resources);
// build JSON response
ResourceToJsonVisitor toJsonVisitor = new ResourceToJsonVisitor();
JsonObject root = marshall(queryData, dataSetSize, resources, toJsonVisitor);
JsonObject root = RestfulHelper.toJson(queryData, dataSetSize, resources, toJsonVisitor);
// marshall result
Gson gson = new GsonBuilder().setPrettyPrinting().create();
@ -122,10 +110,9 @@ public class ModelQuery {
@Produces(MediaType.APPLICATION_JSON)
@Path("orders")
public Response queryOrders(@BeanParam QueryData queryData, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// see if a special realm was requested
String realmName = getRealmName(queryData);
queryData.initializeUnsetFields();
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
List<Order> orders = new ArrayList<>();
@ -134,7 +121,7 @@ public class ModelQuery {
// query the data
long dataSetSize = 0L;
try (StrolchTransaction tx = openTx(cert, realmName)) {
try (StrolchTransaction tx = openTx(cert, queryData.getRealmName())) {
OrderMap orderMap = tx.getOrderMap();
if (query.hasNavigation()) {
@ -152,11 +139,11 @@ public class ModelQuery {
}
// do ordering
doOrdering(queryData, orders);
RestfulHelper.doOrdering(queryData, orders);
// build JSON response
OrderToJsonVisitor toJsonVisitor = new OrderToJsonVisitor();
JsonObject root = marshall(queryData, dataSetSize, orders, toJsonVisitor);
JsonObject root = RestfulHelper.toJson(queryData, dataSetSize, orders, toJsonVisitor);
// marshall result
Gson gson = new GsonBuilder().setPrettyPrinting().create();
@ -179,10 +166,9 @@ public class ModelQuery {
@Produces(MediaType.APPLICATION_JSON)
@Path("activities")
public Response queryActivities(@BeanParam QueryData queryData, @Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// see if a special realm was requested
String realmName = getRealmName(queryData);
queryData.initializeUnsetFields();
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
List<Activity> activities = new ArrayList<>();
@ -191,7 +177,7 @@ public class ModelQuery {
// query the data
long dataSetSize = 0L;
try (StrolchTransaction tx = openTx(cert, realmName)) {
try (StrolchTransaction tx = openTx(cert, queryData.getRealmName())) {
ActivityMap activityMap = tx.getActivityMap();
if (query.hasNavigation()) {
@ -209,11 +195,11 @@ public class ModelQuery {
}
// do ordering
doOrdering(queryData, activities);
RestfulHelper.doOrdering(queryData, activities);
// build JSON response
ActivityToJsonVisitor toJsonVisitor = new ActivityToJsonVisitor();
JsonObject root = marshall(queryData, dataSetSize, activities, toJsonVisitor);
JsonObject root = RestfulHelper.toJson(queryData, dataSetSize, activities, toJsonVisitor);
// marshall result
Gson gson = new GsonBuilder().setPrettyPrinting().create();
@ -221,64 +207,6 @@ public class ModelQuery {
return Response.ok(entity).build();
}
private <T extends StrolchRootElement> JsonObject marshall(QueryData queryData, long dataSetSize, List<T> elements,
StrolchElementVisitor<T, JsonObject> toJsonVisitor) {
// paging
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("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);
if (StringHelper.isNotEmpty(queryData.getOrderBy()))
root.addProperty("sortBy", queryData.getOrderBy());
root.addProperty("ascending", queryData.isAscending());
// add items
JsonArray data = new JsonArray();
for (T t : page) {
JsonObject element = toJsonVisitor.visit(t);
data.add(element);
}
root.add("data", data);
return root;
}
private <T extends StrolchRootElement> void doOrdering(QueryData queryData, List<T> resources) {
if (StringHelper.isNotEmpty(queryData.getOrderBy())) {
if (queryData.getOrderBy().equals(Tags.ID)) {
resources.sort((r1, r2) -> queryData.isAscending() ? r1.getId().compareTo(r2.getId())
: r2.getId().compareTo(r1.getId()));
} else if (queryData.getOrderBy().equals(Tags.NAME)) {
resources.sort((r1, r2) -> queryData.isAscending() ? r1.getName().compareTo(r2.getName())
: r2.getName().compareTo(r1.getName()));
} else if (queryData.getOrderBy().equals(Tags.TYPE)) {
resources.sort((r1, r2) -> queryData.isAscending() ? r1.getType().compareTo(r2.getType())
: r2.getType().compareTo(r1.getType()));
} else {
logger.warn("Unhandled ordering " + queryData.getOrderBy());
}
}
}
private String getRealmName(QueryData queryData) {
String realmName = queryData.getRealmName();
if (StringHelper.isEmpty(realmName))
realmName = StrolchConstants.DEFAULT_REALM;
return realmName;
}
private StrolchTransaction openTx(Certificate certificate, String realm) {
return RestfulStrolchComponent.getInstance().getContainer().getRealm(realm).openTx(certificate,
ModelQuery.class);

View File

@ -2,6 +2,8 @@ package li.strolch.rest.endpoint;
import javax.ws.rs.QueryParam;
import li.strolch.runtime.StrolchConstants;
public class QueryData {
@QueryParam("realmName")
@ -19,8 +21,17 @@ public class QueryData {
@QueryParam("orderBy")
private String orderBy;
@QueryParam("ascending")
private boolean ascending;
@QueryParam("descending")
private boolean descending;
public void initializeUnsetFields() {
if (this.realmName == null)
this.realmName = StrolchConstants.DEFAULT_REALM;
if (this.limit == 0)
this.limit = 50;
if (this.query == null)
this.query = "";
}
public String getRealmName() {
return this.realmName;
@ -38,12 +49,12 @@ public class QueryData {
this.orderBy = orderBy;
}
public boolean isAscending() {
return this.ascending;
public boolean isDescending() {
return this.descending;
}
public void setAscending(boolean ascending) {
this.ascending = ascending;
public void setDescending(boolean descending) {
this.descending = descending;
}
public int getOffset() {

View File

@ -15,13 +15,25 @@
*/
package li.strolch.rest.helper;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.HttpHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.Tags;
import li.strolch.model.visitor.StrolchElementVisitor;
import li.strolch.privilege.model.Certificate;
import li.strolch.rest.StrolchRestfulConstants;
import li.strolch.rest.endpoint.QueryData;
import li.strolch.utils.collections.Paging;
import li.strolch.utils.dbc.DBC;
import li.strolch.utils.helper.StringHelper;
@ -30,6 +42,8 @@ import li.strolch.utils.helper.StringHelper;
*/
public class RestfulHelper {
private static final Logger logger = LoggerFactory.getLogger(RestfulHelper.class);
public static Locale getLocale(HttpHeaders headers) {
if (headers == null || StringHelper.isEmpty(headers.getHeaderString(HttpHeaders.ACCEPT_LANGUAGE)))
return null;
@ -41,4 +55,55 @@ public class RestfulHelper {
DBC.PRE.assertNotNull("Certificate not found as request attribute!", cert);
return cert;
}
public static <T extends StrolchRootElement> JsonObject toJson(QueryData queryData, long dataSetSize,
List<T> elements, StrolchElementVisitor<T, JsonObject> toJsonVisitor) {
// paging
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("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);
if (StringHelper.isNotEmpty(queryData.getOrderBy()))
root.addProperty("sortBy", queryData.getOrderBy());
root.addProperty("descending", queryData.isDescending());
// add items
JsonArray data = new JsonArray();
for (T t : page) {
JsonObject element = toJsonVisitor.visit(t);
data.add(element);
}
root.add("data", data);
return root;
}
public static <T extends StrolchRootElement> void doOrdering(QueryData queryData, List<T> resources) {
if (StringHelper.isNotEmpty(queryData.getOrderBy())) {
if (queryData.getOrderBy().equals(Tags.Json.ID)) {
resources.sort((r1, r2) -> !queryData.isDescending() ? r1.getId().compareTo(r2.getId())
: r2.getId().compareTo(r1.getId()));
} else if (queryData.getOrderBy().equals(Tags.Json.NAME)) {
resources.sort((r1, r2) -> !queryData.isDescending() ? r1.getName().compareTo(r2.getName())
: r2.getName().compareTo(r1.getName()));
} else if (queryData.getOrderBy().equals(Tags.Json.TYPE)) {
resources.sort((r1, r2) -> !queryData.isDescending() ? r1.getType().compareTo(r2.getType())
: r2.getType().compareTo(r1.getType()));
} else {
logger.warn("Unhandled ordering " + queryData.getOrderBy());
}
}
}
}

View File

@ -29,7 +29,14 @@ public class QueryParserTest {
}
@Test
public void shouldParseEmpty() {
public void shouldParseEmpty1() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("", false, false);
assertFalse(query.hasNavigation());
assertFalse(query.hasSelection());
}
@Test
public void shouldParseEmpty2() {
ResourceQuery<Resource> query = QueryParser.parseToResourceQuery("", true, false);
assertFalse(query.hasNavigation());
assertFalse(query.hasSelection());

View File

@ -37,7 +37,6 @@ public class Paging<T> {
private int nextOffset;
private int previousOffset;
private int firstOffset;
private int lastOffset;
private Paging() {
@ -72,13 +71,6 @@ public class Paging<T> {
return this.previousOffset;
}
/**
* @return 0, as the first offset is the first element in the input list
*/
public int getFirstOffset() {
return this.firstOffset;
}
/**
* @return the last possible offset given the offset, limit and input size
*/
@ -124,15 +116,12 @@ public class Paging<T> {
public static <T> Paging<T> asPage(List<T> list, int offset, int limit) {
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();
@ -156,9 +145,9 @@ public class Paging<T> {
} else {
paging.nextOffset = Math.min(paging.size - 1, limit + offset);
paging.lastOffset = paging.size % limit == 0 ? paging.size - limit : ((int) paging.size / limit) * limit;
paging.nextOffset = Math.min(paging.lastOffset, limit + offset);
paging.previousOffset = Math.max(0, offset - limit);
paging.lastOffset = offset + ((paging.size - offset) - ((paging.size - offset) % limit));
}
return paging;

View File

@ -90,14 +90,12 @@ public class PagingTest {
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());
}
@ -113,7 +111,6 @@ public class PagingTest {
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());
}
@ -125,15 +122,26 @@ public class PagingTest {
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(0, paging.getOffset());
assertEquals(0, paging.getPreviousOffset());
assertEquals(3, paging.getNextOffset());
assertEquals(6, paging.getLastOffset());
page = Paging.asPage(list, paging.getNextOffset(), paging.getLimit()).getPage();
paging = Paging.asPage(list, paging.getNextOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("d", "e", "f"), page);
assertEquals(3, paging.getOffset());
assertEquals(0, paging.getPreviousOffset());
assertEquals(6, paging.getNextOffset());
assertEquals(6, paging.getLastOffset());
page = Paging.asPage(list, paging.getLastOffset(), paging.getLimit()).getPage();
paging = Paging.asPage(list, paging.getLastOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("g"), page);
assertEquals(6, paging.getOffset());
assertEquals(3, paging.getPreviousOffset());
assertEquals(6, paging.getNextOffset());
assertEquals(6, paging.getLastOffset());
}
@Test
@ -144,13 +152,20 @@ public class PagingTest {
List<String> page = paging.getPage();
assertEquals(Arrays.asList("b"), page);
page = Paging.asPage(list, paging.getPreviousOffset(), paging.getLimit()).getPage();
paging = Paging.asPage(list, paging.getPreviousOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("a"), page);
page = Paging.asPage(list, paging.getNextOffset(), paging.getLimit()).getPage();
paging = Paging.asPage(list, paging.getNextOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("b"), page);
paging = Paging.asPage(list, paging.getNextOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("c"), page);
page = Paging.asPage(list, paging.getLastOffset(), paging.getLimit()).getPage();
paging = Paging.asPage(list, paging.getLastOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("g"), page);
}
@ -162,13 +177,45 @@ public class PagingTest {
List<String> page = paging.getPage();
assertEquals(Arrays.asList("c", "d"), page);
page = Paging.asPage(list, paging.getPreviousOffset(), paging.getLimit()).getPage();
paging = Paging.asPage(list, paging.getPreviousOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("a", "b"), page);
page = Paging.asPage(list, paging.getNextOffset(), paging.getLimit()).getPage();
assertEquals(Arrays.asList("e", "f"), page);
paging = Paging.asPage(list, paging.getNextOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("c", "d"), page);
page = Paging.asPage(list, paging.getLastOffset(), paging.getLimit()).getPage();
assertEquals(Arrays.asList("g"), page);
paging = Paging.asPage(list, paging.getNextOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("e", "f"), page);
}
@Test
public void shouldReturnLastPage8() {
List<String> list = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11");
Paging<String> paging = Paging.asPage(list, 0, 5);
List<String> page = paging.getPage();
assertEquals(Arrays.asList("0", "1", "2", "3", "4"), page);
assertEquals(0, paging.getOffset());
assertEquals(0, paging.getPreviousOffset());
assertEquals(5, paging.getNextOffset());
assertEquals(10, paging.getLastOffset());
paging = Paging.asPage(list, paging.getNextOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("5", "6", "7", "8", "9"), page);
assertEquals(5, paging.getOffset());
assertEquals(0, paging.getPreviousOffset());
assertEquals(10, paging.getNextOffset());
assertEquals(10, paging.getLastOffset());
paging = Paging.asPage(list, paging.getNextOffset(), paging.getLimit());
page = paging.getPage();
assertEquals(Arrays.asList("10", "11"), page);
assertEquals(10, paging.getOffset());
assertEquals(5, paging.getPreviousOffset());
assertEquals(10, paging.getNextOffset());
assertEquals(10, paging.getLastOffset());
}
}