From 0e5176df6276622904f4eecec073f45a00e32f99 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 8 Feb 2017 20:16:05 +0100 Subject: [PATCH] [Major] Inspector now has offset/limit for queries --- .../li/strolch/rest/endpoint/Inspector.java | 151 ++++++++++-------- .../li/strolch/rest/endpoint/ModelQuery.java | 104 ++---------- .../li/strolch/rest/endpoint/QueryData.java | 23 ++- .../li/strolch/rest/helper/RestfulHelper.java | 65 ++++++++ .../model/query/parser/QueryParserTest.java | 9 +- .../li/strolch/utils/collections/Paging.java | 15 +- .../strolch/utils/collections/PagingTest.java | 75 +++++++-- 7 files changed, 252 insertions(+), 190 deletions(-) diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java index 5aff3cd37..ebad50364 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java @@ -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 @@ -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 resources = new ArrayList<>(); - JsonArray elementsJ = new JsonArray(); - typeDetailJ.add(Tags.Json.ELEMENTS, elementsJ); + // parse the query string + ResourceQuery 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 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 orders = new ArrayList<>(); - JsonArray elementsJ = new JsonArray(); - typeDetailJ.add(Tags.Json.ELEMENTS, elementsJ); + // parse the query string + OrderQuery query = QueryParser.parseToOrderQuery(queryData.getQuery(), true, true); + query.setNavigation(new StrolchTypeNavigation(type)); - try (StrolchTransaction tx = openTx(cert, realm)) { - - List 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 activities = new ArrayList<>(); - JsonArray elementsJ = new JsonArray(); - typeDetailJ.add(Tags.Json.ELEMENTS, elementsJ); + // parse the query string + ActivityQuery query = QueryParser.parseToActivityQuery(queryData.getQuery(), true, true); + query.setNavigation(new StrolchTypeNavigation(type)); - try (StrolchTransaction tx = openTx(cert, realm)) { - - List 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 diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/ModelQuery.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/ModelQuery.java index 383ff7c0c..eb84a3207 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/ModelQuery.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/ModelQuery.java @@ -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 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 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 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 JsonObject marshall(QueryData queryData, long dataSetSize, List elements, - StrolchElementVisitor toJsonVisitor) { - - // paging - Paging paging = Paging.asPage(elements, queryData.getOffset(), queryData.getLimit()); - - // get page - List 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 void doOrdering(QueryData queryData, List 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); diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/QueryData.java b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/QueryData.java index f236cf753..c66ed4087 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/QueryData.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/endpoint/QueryData.java @@ -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() { diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/helper/RestfulHelper.java b/li.strolch.rest/src/main/java/li/strolch/rest/helper/RestfulHelper.java index 73e24bf48..dec593602 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/helper/RestfulHelper.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/helper/RestfulHelper.java @@ -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 JsonObject toJson(QueryData queryData, long dataSetSize, + List elements, StrolchElementVisitor toJsonVisitor) { + + // paging + Paging paging = Paging.asPage(elements, queryData.getOffset(), queryData.getLimit()); + + // get page + List 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 void doOrdering(QueryData queryData, List 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()); + } + } + } } diff --git a/li.strolch.rest/src/test/java/li/strolch/model/query/parser/QueryParserTest.java b/li.strolch.rest/src/test/java/li/strolch/model/query/parser/QueryParserTest.java index 98cb86949..9cb94f8ad 100644 --- a/li.strolch.rest/src/test/java/li/strolch/model/query/parser/QueryParserTest.java +++ b/li.strolch.rest/src/test/java/li/strolch/model/query/parser/QueryParserTest.java @@ -29,7 +29,14 @@ public class QueryParserTest { } @Test - public void shouldParseEmpty() { + public void shouldParseEmpty1() { + ResourceQuery query = QueryParser.parseToResourceQuery("", false, false); + assertFalse(query.hasNavigation()); + assertFalse(query.hasSelection()); + } + + @Test + public void shouldParseEmpty2() { ResourceQuery query = QueryParser.parseToResourceQuery("", true, false); assertFalse(query.hasNavigation()); assertFalse(query.hasSelection()); diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/collections/Paging.java b/li.strolch.utils/src/main/java/li/strolch/utils/collections/Paging.java index 7b6a4af34..2291630e5 100644 --- a/li.strolch.utils/src/main/java/li/strolch/utils/collections/Paging.java +++ b/li.strolch.utils/src/main/java/li/strolch/utils/collections/Paging.java @@ -37,7 +37,6 @@ public class Paging { private int nextOffset; private int previousOffset; - private int firstOffset; private int lastOffset; private Paging() { @@ -72,13 +71,6 @@ public class Paging { 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 { public static Paging asPage(List list, int offset, int limit) { Paging 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 { } 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; diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/collections/PagingTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/collections/PagingTest.java index 10e52eaf2..311d10cd7 100644 --- a/li.strolch.utils/src/test/java/li/strolch/utils/collections/PagingTest.java +++ b/li.strolch.utils/src/test/java/li/strolch/utils/collections/PagingTest.java @@ -90,14 +90,12 @@ public class PagingTest { Paging paging = Paging.asPage(list, 0, 2); List 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 paging = Paging.asPage(list, 0, 3); List 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 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 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 list = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"); + + Paging paging = Paging.asPage(list, 0, 5); + List 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()); } }