From 02d84be812a0cf223de74998870e497d48309c91 Mon Sep 17 00:00:00 2001 From: Keerthi B L Date: Fri, 17 Nov 2023 13:51:33 +0530 Subject: [PATCH] fix (rest) : rest api created for component search by lucene search Signed-off-by: Keerthi B L --- .../src/docs/asciidoc/components.adoc | 17 ++++ .../component/ComponentController.java | 86 +++++++++++++------ .../component/Sw360ComponentService.java | 5 ++ .../restdocs/ComponentSpecTest.java | 31 +++++++ 4 files changed, 114 insertions(+), 25 deletions(-) diff --git a/rest/resource-server/src/docs/asciidoc/components.adoc b/rest/resource-server/src/docs/asciidoc/components.adoc index e248c04717..0db63a49a7 100644 --- a/rest/resource-server/src/docs/asciidoc/components.adoc +++ b/rest/resource-server/src/docs/asciidoc/components.adoc @@ -48,6 +48,23 @@ include::{snippets}/should_document_get_components_with_all_details/curl-request ===== Example response include::{snippets}/should_document_get_components_with_all_details/http-response.adoc[] +[[resources-components-list-with-lucenesearch]] +==== Listing by lucene search + +A `GET` request will list all of the service's components by lucenesearch. + +===== Response structure +include::{snippets}/should_document_get_components_by_lucene_search/response-fields.adoc[] + +===== Example request +include::{snippets}/should_document_get_components_by_lucene_search/curl-request.adoc[] + +===== Example response +include::{snippets}/should_document_get_components_by_lucene_search/http-response.adoc[] + +===== Links +include::{snippets}/should_document_get_components_by_lucene_search/links.adoc[] + [[resources-recent-components-list]] ==== Listing recent components diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/component/ComponentController.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/component/ComponentController.java index 821dac9f90..6329fb0568 100644 --- a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/component/ComponentController.java +++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/component/ComponentController.java @@ -23,6 +23,7 @@ import org.eclipse.sw360.datahandler.common.CommonUtils; import org.eclipse.sw360.datahandler.common.SW360Constants; import org.eclipse.sw360.datahandler.common.SW360Utils; +import org.eclipse.sw360.datahandler.couchdb.lucene.LuceneAwareDatabaseConnector; import org.eclipse.sw360.datahandler.resourcelists.PaginationParameterException; import org.eclipse.sw360.datahandler.resourcelists.PaginationResult; import org.eclipse.sw360.datahandler.resourcelists.ResourceClassNotFoundException; @@ -90,6 +91,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; @@ -141,6 +144,8 @@ public ResponseEntity>> getComponents( @RequestParam(value = "fields", required = false) List fields, @Parameter(description = "Flag to get components with all details.") @RequestParam(value = "allDetails", required = false) boolean allDetails, + @Parameter(description = "lucenesearch parameter to filter the components.") + @RequestParam(value = "luceneSearch", required = false) boolean luceneSearch, HttpServletRequest request ) throws TException, URISyntaxException, PaginationParameterException, ResourceClassNotFoundException { @@ -150,42 +155,73 @@ public ResponseEntity>> getComponents( String queryString = request.getQueryString(); Map params = parseQueryString(queryString); - if (name != null && !name.isEmpty()) { - allComponents.addAll(componentService.searchComponentByName(params.get("name").replace("%20"," "))); + Map> filterMap = new HashMap<>(); + if (luceneSearch) { + if (CommonUtils.isNotNullEmptyOrWhitespace(componentType)) { + Set values = CommonUtils.splitToSet(componentType); + filterMap.put(Component._Fields.COMPONENT_TYPE.getFieldName(), values); + } + if (CommonUtils.isNotNullEmptyOrWhitespace(name)) { + Set values = CommonUtils.splitToSet(name); + values = values.stream().map(LuceneAwareDatabaseConnector::prepareWildcardQuery) + .collect(Collectors.toSet()); + filterMap.put(Component._Fields.NAME.getFieldName(), values); + } + allComponents.addAll(componentService.refineSearch(filterMap, sw360User)); } else { - allComponents.addAll(componentService.getComponentsForUser(sw360User)); + if (name != null && !name.isEmpty()) { + allComponents.addAll(componentService.searchComponentByName(params.get("name").replace("%20", " "))); + } else { + allComponents.addAll(componentService.getComponentsForUser(sw360User)); + } } - PaginationResult paginationResult = restControllerHelper.createPaginationResult(request, pageable, allComponents, SW360Constants.TYPE_COMPONENT); + PaginationResult paginationResult = restControllerHelper.createPaginationResult(request, pageable, + allComponents, SW360Constants.TYPE_COMPONENT); + + CollectionModel resources = getFilteredComponentResources(componentType, fields, allDetails, luceneSearch, + sw360User, paginationResult); + return new ResponseEntity<>(resources, HttpStatus.OK); + } + private CollectionModel getFilteredComponentResources(String componentType, List fields, boolean allDetails, + boolean luceneSearch, User sw360User, PaginationResult paginationResult) + throws URISyntaxException { List> componentResources = new ArrayList<>(); - paginationResult.getResources().stream() - .filter(component -> componentType == null || (component.isSetComponentType() && componentType.equals(component.componentType.name()))) - .forEach(c -> { - EntityModel embeddedComponentResource = null; - if (!allDetails) { - Component embeddedComponent = restControllerHelper.convertToEmbeddedComponent(c, fields); - embeddedComponentResource = EntityModel.of(embeddedComponent); - } else { - try { - embeddedComponentResource = createHalComponent(c, sw360User); - } catch (TException e) { - throw new RuntimeException(e); - } - if (embeddedComponentResource == null) { - return; - } - } - componentResources.add(embeddedComponentResource); - }); + Consumer consumer = c -> { + EntityModel embeddedComponentResource = null; + if (!allDetails) { + Component embeddedComponent = restControllerHelper.convertToEmbeddedComponent(c, fields); + embeddedComponentResource = EntityModel.of(embeddedComponent); + } else { + try { + embeddedComponentResource = createHalComponent(c, sw360User); + } catch (TException e) { + throw new RuntimeException(e); + } + if (embeddedComponentResource == null) { + return; + } + } + componentResources.add(embeddedComponentResource); + }; + + if (luceneSearch) { + paginationResult.getResources().stream().forEach(consumer); + } else { + paginationResult.getResources().stream() + .filter(component -> componentType == null + || (component.isSetComponentType() && componentType.equals(component.componentType.name()))) + .forEach(consumer); + } CollectionModel resources; - if (componentResources.size() == 0) { + if (componentResources.isEmpty()) { resources = restControllerHelper.emptyPageResource(Component.class, paginationResult); } else { resources = restControllerHelper.generatePagesResource(paginationResult, componentResources); } - return new ResponseEntity<>(resources, HttpStatus.OK); + return resources; } private Map parseQueryString(String queryString) { diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/component/Sw360ComponentService.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/component/Sw360ComponentService.java index c6f8f901b5..c32b7cbf63 100644 --- a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/component/Sw360ComponentService.java +++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/component/Sw360ComponentService.java @@ -323,4 +323,9 @@ public int countProjectsByComponentId(String componentId, User sw360user) throws Set releaseIds = SW360Utils.getReleaseIds(component.getReleases()); return projectService.countProjectsByReleaseIds(releaseIds); } + + public List refineSearch(Map> filterMap, User sw360User) throws TException { + ComponentService.Iface sw360ComponentClient = getThriftComponentClient(); + return sw360ComponentClient.refineSearchAccessibleComponents(null, filterMap, sw360User); + } } diff --git a/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/ComponentSpecTest.java b/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/ComponentSpecTest.java index b139b5dc1c..bee2e7af86 100644 --- a/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/ComponentSpecTest.java +++ b/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/ComponentSpecTest.java @@ -311,6 +311,7 @@ public void before() throws TException, IOException { given(this.componentServiceMock.getComponentsForUser(any())).willReturn(componentList); given(this.sw360ReportServiceMock.getComponentBuffer(any(),anyBoolean())).willReturn(ByteBuffer.allocate(10000)); given(this.componentServiceMock.getRecentComponents(any())).willReturn(componentList); + given(this.componentServiceMock.refineSearch(any(), any())).willReturn(componentList); given(this.componentServiceMock.getComponentSubscriptions(any())).willReturn(componentList); given(this.componentServiceMock.getMyComponentsForUser(any())).willReturn(componentList); given(this.componentServiceMock.getComponentForUserById(eq("17653524"), any())).willReturn(angularComponent); @@ -549,6 +550,36 @@ public void should_document_get_components() throws Exception { ))); } + @Test + public void should_document_get_components_by_lucene_search() throws Exception { + String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword); + mockMvc.perform(get("/api/components").header("Authorization", "Bearer " + accessToken) + .param("name", angularComponent.getName()).param("luceneSearch", "true").param("sort", "name,desc") + .param("page", "0").param("page_entries", "5").accept(MediaTypes.HAL_JSON)).andExpect(status().isOk()) + .andDo(this.documentationHandler.document( + requestParameters(parameterWithName("name").description("name of components"), + parameterWithName("luceneSearch").description("Defines whether luceneSearch is required while searching the component"), + parameterWithName("page").description("Page of components"), + parameterWithName("page_entries").description("Amount of components per page"), + parameterWithName("sort").description("Defines order of the components")), + links(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:components.[]id").description("The id of the component"), + subsectionWithPath("_embedded.sw360:components.[]name").description("The name of the component"), + subsectionWithPath("_embedded.sw360:components.[]componentType").description("The component type, possible values are: "+ Arrays.asList(ComponentType.values())), + subsectionWithPath("_embedded.sw360:components.[]visbility").description("The visbility of the component"), + subsectionWithPath("_embedded.sw360:components.[]description").description("The description of the component"), + subsectionWithPath("_embedded.sw360:components").description("An array of <>"), + subsectionWithPath("_links").description("<> to other resources"), + fieldWithPath("page").description("Additional paging information"), + fieldWithPath("page.size").description("Number of components per page"), + fieldWithPath("page.totalElements").description("Total number of all existing components"), + fieldWithPath("page.totalPages").description("Total number of pages"), + fieldWithPath("page.number").description("Number of the current page")))); + } + @Test public void should_document_get_components_with_all_details() throws Exception { String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword);