From c7c33c78f1c317dedf00e7de166f466a7e5dc986 Mon Sep 17 00:00:00 2001 From: rudra-superrr Date: Fri, 17 Nov 2023 12:08:44 +0530 Subject: [PATCH] feat(rest): adding pagination for listing vendors endpoint. Signed-off-by: rudra-superrr --- .../ResourceComparatorGenerator.java | 45 +++++++++++++++++++ .../src/docs/asciidoc/vendors.adoc | 3 ++ .../vendor/VendorController.java | 31 ++++++++++--- .../restdocs/VendorSpecTest.java | 19 +++++++- 4 files changed, 90 insertions(+), 8 deletions(-) diff --git a/libraries/datahandler/src/main/java/org/eclipse/sw360/datahandler/resourcelists/ResourceComparatorGenerator.java b/libraries/datahandler/src/main/java/org/eclipse/sw360/datahandler/resourcelists/ResourceComparatorGenerator.java index 3ca4194754..efbb9a34fc 100644 --- a/libraries/datahandler/src/main/java/org/eclipse/sw360/datahandler/resourcelists/ResourceComparatorGenerator.java +++ b/libraries/datahandler/src/main/java/org/eclipse/sw360/datahandler/resourcelists/ResourceComparatorGenerator.java @@ -27,6 +27,7 @@ import org.eclipse.sw360.datahandler.thrift.packages.Package; import org.eclipse.sw360.datahandler.thrift.projects.Project; import org.eclipse.sw360.datahandler.thrift.users.User; +import org.eclipse.sw360.datahandler.thrift.vendors.Vendor; import org.eclipse.sw360.datahandler.thrift.search.SearchResult; import org.eclipse.sw360.datahandler.thrift.vulnerabilities.VulnerabilityDTO; import org.eclipse.sw360.datahandler.thrift.vulnerabilities.Vulnerability; @@ -37,6 +38,7 @@ public class ResourceComparatorGenerator { private static final Map> projectMap = generateProjectMap(); private static final Map> userMap = generateUserMap(); private static final Map> releaseMap = generateReleaseMap(); + private static final Map> vendorMap = generateVendorMap(); private static final Map> packageMap = generatePackageMap(); private static final Map> searchResultMap = generateSearchResultMap(); private static final Map> changeLogMap = generateChangeLogMap(); @@ -77,6 +79,13 @@ private static Map> generateReleaseMap() { return Collections.unmodifiableMap(releaseMap); } + private static Map> generateVendorMap() { + Map> vendorMap = new HashMap<>(); + vendorMap.put(Vendor._Fields.FULLNAME, Comparator.comparing(Vendor::getFullname, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER))); + vendorMap.put(Vendor._Fields.SHORTNAME, Comparator.comparing(Vendor::getShortname, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER))); + return Collections.unmodifiableMap(vendorMap); + } + private static Map> generatePackageMap() { Map> packageMap = new HashMap<>(); packageMap.put(Package._Fields.NAME, Comparator.comparing(Package::getName, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER))); @@ -137,6 +146,8 @@ public Comparator generateComparator(String type) throws ResourceClassNotFoun return (Comparator)defaultUserComparator(); case SW360Constants.TYPE_RELEASE: return (Comparator)defaultReleaseComparator(); + case SW360Constants.TYPE_VENDOR: + return (Comparator)defaultVendorComparator(); case SW360Constants.TYPE_SEARCHRESULT: return (Comparator)defaultSearchResultComparator(); case SW360Constants.TYPE_CHANGELOG: @@ -196,6 +207,15 @@ public Comparator generateComparator(String type, List properties) th } } return generateReleaseComparatorWithFields(type, releaeFields); + case SW360Constants.TYPE_VENDOR: + List vendorFields = new ArrayList<>(); + for(String property:properties) { + Vendor._Fields field = Vendor._Fields.findByName(property); + if (field != null) { + vendorFields.add(field); + } + } + return generateVendorComparatorWithFields(type, vendorFields); case SW360Constants.TYPE_PACKAGE: List packageFields = new ArrayList<>(); for (String property:properties) { @@ -282,6 +302,15 @@ public Comparator generateReleaseComparatorWithFields(String type, List generateVendorComparatorWithFields(String type, List fields) throws ResourceClassNotFoundException { + switch (type) { + case SW360Constants.TYPE_VENDOR: + return (Comparator)vendorComparator(fields); + default: + throw new ResourceClassNotFoundException("No comparator for resource class with name " + type); + } + } + public Comparator generatePackageComparatorWithFields(String type, List fields) throws ResourceClassNotFoundException { switch (type) { case SW360Constants.TYPE_PACKAGE: @@ -376,6 +405,18 @@ private Comparator releaseComparator(List fields) { return comparator; } + private Comparator vendorComparator(List fields) { + Comparator comparator = Comparator.comparing(x -> true); + for (Vendor._Fields field:fields) { + Comparator fieldComparator = vendorMap.get(field); + if(fieldComparator != null) { + comparator = comparator.thenComparing(fieldComparator); + } + } + comparator = comparator.thenComparing(defaultVendorComparator()); + return comparator; + } + private Comparator packageComparator(List fields) { Comparator comparator = Comparator.comparing(x -> true); for (Package._Fields field:fields) { @@ -452,6 +493,10 @@ private Comparator defaultReleaseComparator() { return releaseMap.get(Release._Fields.NAME); } + private Comparator defaultVendorComparator() { + return vendorMap.get(Vendor._Fields.FULLNAME); + } + private Comparator defaultSearchResultComparator() { return searchResultMap.get(SearchResult._Fields.NAME); } diff --git a/rest/resource-server/src/docs/asciidoc/vendors.adoc b/rest/resource-server/src/docs/asciidoc/vendors.adoc index 7f71f9280b..82198d1ea2 100644 --- a/rest/resource-server/src/docs/asciidoc/vendors.adoc +++ b/rest/resource-server/src/docs/asciidoc/vendors.adoc @@ -19,6 +19,9 @@ The Vendors resource is used to create and list vendors. A `GET` request will list all of the service's vendors. +===== Request parameter +include::{snippets}/should_document_get_vendors/request-parameters.adoc[] + ===== Response structure include::{snippets}/should_document_get_vendors/response-fields.adoc[] diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/VendorController.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/VendorController.java index 9c066d8fbe..125ecbd7a5 100644 --- a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/VendorController.java +++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/VendorController.java @@ -31,8 +31,15 @@ import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import org.eclipse.sw360.datahandler.resourcelists.PaginationParameterException; +import org.eclipse.sw360.datahandler.resourcelists.PaginationResult; +import org.eclipse.sw360.datahandler.resourcelists.ResourceClassNotFoundException; +import org.eclipse.sw360.datahandler.common.SW360Constants; +import org.springframework.data.domain.Pageable; import java.io.IOException; +import java.net.URISyntaxException; +import javax.servlet.http.HttpServletRequest; import java.net.URI; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -40,6 +47,7 @@ import javax.servlet.http.HttpServletResponse; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; +import static org.eclipse.sw360.datahandler.common.WrappedException.wrapTException; @BasePathAwareController @RequiredArgsConstructor(onConstructor = @__(@Autowired)) @@ -52,7 +60,7 @@ public class VendorController implements RepresentationModelProcessor restControllerHelper; + private final RestControllerHelper restControllerHelper; @Operation( summary = "List all of the service's vendors.", @@ -60,17 +68,28 @@ public class VendorController implements RepresentationModelProcessor>> getVendors() { + public ResponseEntity>> getVendors( + Pageable pageable, + HttpServletRequest request + ) throws TException, URISyntaxException, PaginationParameterException, ResourceClassNotFoundException { List vendors = vendorService.getVendors(); + PaginationResult paginationResult = restControllerHelper.createPaginationResult(request, pageable, vendors, SW360Constants.TYPE_VENDOR); List> vendorResources = new ArrayList<>(); - vendors.forEach(v -> { + for (Vendor v: paginationResult.getResources()) { Vendor embeddedVendor = restControllerHelper.convertToEmbeddedVendor(v); vendorResources.add(EntityModel.of(embeddedVendor)); - }); + } + + CollectionModel> resources; + if (vendors.size() == 0) { + resources = restControllerHelper.emptyPageResource(Vendor.class, paginationResult); + } else { + resources = restControllerHelper.generatePagesResource(paginationResult, vendorResources); + } - CollectionModel> resources = CollectionModel.of(vendorResources); - return new ResponseEntity<>(resources, HttpStatus.OK); + HttpStatus status = resources == null ? HttpStatus.NO_CONTENT : HttpStatus.OK; + return new ResponseEntity<>(resources, status); } @Operation( diff --git a/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/VendorSpecTest.java b/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/VendorSpecTest.java index 1230f5b005..e5eb9b1a1c 100644 --- a/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/VendorSpecTest.java +++ b/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/VendorSpecTest.java @@ -40,6 +40,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; @RunWith(SpringJUnit4ClassRunner.class) public class VendorSpecTest extends TestRestDocsSpecBase { @@ -86,18 +88,31 @@ public void should_document_get_vendors() throws Exception { String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword); mockMvc.perform(get("/api/vendors") .header("Authorization", "Bearer " + accessToken) + .param("page", "0") + .param("page_entries", "5") .accept(MediaTypes.HAL_JSON)) .andExpect(status().isOk()) .andDo(this.documentationHandler.document( + requestParameters( + parameterWithName("page").description("Page of vendors"), + parameterWithName("page_entries").description("Amount of vendors per page") + ), links( - linkWithRel("curies").description("Curies are used for online documentation") + linkWithRel("curies").description("Curies are used for online documentation"), + linkWithRel("first").description("Link to first page"), + linkWithRel("last").description("Link to last page") ), responseFields( subsectionWithPath("_embedded.sw360:vendors.[]fullName").description("The full name of the vendor"), subsectionWithPath("_embedded.sw360:vendors.[]shortName").description("The Short Name of the vendor"), subsectionWithPath("_embedded.sw360:vendors.[]url").description("The Url of the vendor"), subsectionWithPath("_embedded.sw360:vendors").description("An array of <>"), - subsectionWithPath("_links").description("<> to other resources") + subsectionWithPath("_links").description("<> to other resources"), + fieldWithPath("page").description("Additional paging information"), + fieldWithPath("page.size").description("Number of vendors per page"), + fieldWithPath("page.totalElements").description("Total number of all existing vendors"), + fieldWithPath("page.totalPages").description("Total number of pages"), + fieldWithPath("page.number").description("Number of the current page") ))); }