Skip to content

Commit 471856d

Browse files
authored
Merge pull request #2166 from siemens/feat/PaginationForVuln
fix(rest) : adding pagination for listing vulnerabilities endpoint Reviewed by: anupam.ghosh@siemens.com Tested by: kumar.nikesh@siemens.com
2 parents 83dae9f + 2c8d020 commit 471856d

File tree

5 files changed

+98
-9
lines changed

5 files changed

+98
-9
lines changed

libraries/datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public class SW360Constants {
8080
public static final String TYPE_SEARCHRESULT = "searchResult";
8181
public static final String TYPE_CHANGELOG = "changeLog";
8282
public static final String TYPE_VULNERABILITYDTO = "vulDTO";
83+
public static final String TYPE_VULNERABILITY = "vul";
8384
public static final String TYPE_OBLIGATIONELEMENT = "obligationElement";
8485
public static final String TYPE_OBLIGATIONNODE = "obligationNode";
8586
public static final String TYPE_DOCUMENT = "document";

libraries/datahandler/src/main/java/org/eclipse/sw360/datahandler/resourcelists/ResourceComparatorGenerator.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.eclipse.sw360.datahandler.thrift.projects.Project;
2929
import org.eclipse.sw360.datahandler.thrift.search.SearchResult;
3030
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.VulnerabilityDTO;
31+
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.Vulnerability;
3132

3233
public class ResourceComparatorGenerator<T> {
3334

@@ -38,6 +39,7 @@ public class ResourceComparatorGenerator<T> {
3839
private static final Map<SearchResult._Fields, Comparator<SearchResult>> searchResultMap = generateSearchResultMap();
3940
private static final Map<ChangeLogs._Fields, Comparator<ChangeLogs>> changeLogMap = generateChangeLogMap();
4041
private static final Map<VulnerabilityDTO._Fields, Comparator<VulnerabilityDTO>> vDtoMap = generateVulDtoMap();
42+
private static final Map<Vulnerability._Fields, Comparator<Vulnerability>> vMap = generateVulMap();
4143
private static final Map<ModerationRequest._Fields, Comparator<ModerationRequest>> moderationRequestMap = generateModerationRequestMap();
4244

4345
private static Map<Component._Fields, Comparator<Component>> generateComponentMap() {
@@ -95,6 +97,14 @@ private static Map<VulnerabilityDTO._Fields, Comparator<VulnerabilityDTO>> gener
9597
return Collections.unmodifiableMap(vulDTOMap);
9698
}
9799

100+
private static Map<Vulnerability._Fields, Comparator<Vulnerability>> generateVulMap() {
101+
Map<Vulnerability._Fields, Comparator<Vulnerability>> vulMap = new HashMap<>();
102+
vulMap.put(Vulnerability._Fields.EXTERNAL_ID, Comparator.comparing(Vulnerability::getExternalId, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
103+
vulMap.put(Vulnerability._Fields.TITLE, Comparator.comparing(Vulnerability::getTitle, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
104+
vulMap.put(Vulnerability._Fields.PRIORITY, Comparator.comparing(Vulnerability::getPriority, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
105+
return Collections.unmodifiableMap(vulMap);
106+
}
107+
98108
private static Map<ModerationRequest._Fields, Comparator<ModerationRequest>> generateModerationRequestMap() {
99109
Map<ModerationRequest._Fields, Comparator<ModerationRequest>> moderationRequestMap = new HashMap<>();
100110
moderationRequestMap.put(ModerationRequest._Fields.TIMESTAMP,
@@ -122,6 +132,8 @@ public Comparator<T> generateComparator(String type) throws ResourceClassNotFoun
122132
return (Comparator<T>)defaultChangeLogComparator();
123133
case SW360Constants.TYPE_VULNERABILITYDTO:
124134
return (Comparator<T>)defaultVulDtoComparator();
135+
case SW360Constants.TYPE_VULNERABILITY:
136+
return (Comparator<T>)defaultVulComparator();
125137
case SW360Constants.TYPE_MODERATION:
126138
return (Comparator<T>)defaultModerationRequestComparator();
127139
case SW360Constants.TYPE_PACKAGE:
@@ -200,6 +212,15 @@ public Comparator<T> generateComparator(String type, List<String> properties) th
200212
}
201213
}
202214
return generateVulDTOComparatorWithFields(type, vulDtos);
215+
case SW360Constants.TYPE_VULNERABILITY:
216+
List<Vulnerability._Fields> vul = new ArrayList<>();
217+
for(String property : properties) {
218+
Vulnerability._Fields field = Vulnerability._Fields.findByName(property);
219+
if (field != null) {
220+
vul.add(field);
221+
}
222+
}
223+
return generateVulComparatorWithFields(type, vul);
203224
default:
204225
throw new ResourceClassNotFoundException("No comparator for resource class with name " + type);
205226
}
@@ -268,6 +289,16 @@ public Comparator<T> generateVulDTOComparatorWithFields(String type, List<Vulner
268289
}
269290
}
270291

292+
public Comparator<T> generateVulComparatorWithFields(String type, List<Vulnerability._Fields> fields) throws ResourceClassNotFoundException {
293+
switch (type) {
294+
case SW360Constants.TYPE_VULNERABILITY:
295+
return (Comparator<T>)vulnComparator(fields);
296+
default:
297+
throw new ResourceClassNotFoundException("No comparator for resource class with name " + type);
298+
}
299+
}
300+
301+
271302
private Comparator<Component> componentComparator(List<Component._Fields> fields) {
272303
Comparator<Component> comparator = Comparator.comparing(x -> true);
273304
for (Component._Fields field:fields) {
@@ -352,6 +383,18 @@ private Comparator<VulnerabilityDTO> vulnDtoComparator(List<VulnerabilityDTO._Fi
352383
return comparator;
353384
}
354385

386+
private Comparator<Vulnerability> vulnComparator(List<Vulnerability._Fields> fields) {
387+
Comparator<Vulnerability> comparator = Comparator.comparing(x -> true);
388+
for (Vulnerability._Fields field:fields) {
389+
Comparator<Vulnerability> fieldComparator = vMap.get(field);
390+
if(fieldComparator != null) {
391+
comparator = comparator.thenComparing(fieldComparator);
392+
}
393+
}
394+
comparator = comparator.thenComparing(defaultVulComparator());
395+
return comparator;
396+
}
397+
355398
private Comparator<Component> defaultComponentComparator() {
356399
return componentMap.get(Component._Fields.NAME);
357400
}
@@ -376,6 +419,10 @@ private Comparator<VulnerabilityDTO> defaultVulDtoComparator() {
376419
return vDtoMap.get(VulnerabilityDTO._Fields.EXTERNAL_ID);
377420
}
378421

422+
private Comparator<Vulnerability> defaultVulComparator() {
423+
return vMap.get(Vulnerability._Fields.EXTERNAL_ID);
424+
}
425+
379426
private Comparator<ModerationRequest> defaultModerationRequestComparator() {
380427
return moderationRequestMap.get(ModerationRequest._Fields.TIMESTAMP);
381428
}

rest/resource-server/src/docs/asciidoc/vulnerabilities.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ The Vulnerabilities resource is used to create and list vulnerabilities.
1919

2020
A `GET` request will list all of the service's vulnerabilities.
2121

22+
===== Request parameter
23+
include::{snippets}/should_document_get_vulnerabilities/request-parameters.adoc[]
24+
2225
===== Response structure
2326
include::{snippets}/should_document_get_vulnerabilities/response-fields.adoc[]
2427

rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vulnerability/VulnerabilityController.java

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import lombok.extern.slf4j.Slf4j;
1717

1818
import java.net.URI;
19+
import java.net.URISyntaxException;
1920
import java.util.Map;
2021
import java.util.Objects;
2122
import java.util.Optional;
@@ -25,11 +26,17 @@
2526
import java.util.stream.Collectors;
2627

2728
import javax.websocket.server.PathParam;
29+
import javax.servlet.http.HttpServletRequest;
30+
2831

2932
import org.apache.thrift.TException;
3033
import org.eclipse.sw360.datahandler.common.CommonUtils;
34+
import org.eclipse.sw360.datahandler.common.SW360Constants;
3135
import org.eclipse.sw360.datahandler.common.SW360Utils;
3236
import org.eclipse.sw360.datahandler.permissions.DocumentPermissions;
37+
import org.eclipse.sw360.datahandler.resourcelists.PaginationParameterException;
38+
import org.eclipse.sw360.datahandler.resourcelists.PaginationResult;
39+
import org.eclipse.sw360.datahandler.resourcelists.ResourceClassNotFoundException;
3340
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
3441
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
3542
import org.eclipse.sw360.datahandler.thrift.components.Release;
@@ -44,6 +51,7 @@
4451
import org.eclipse.sw360.rest.resourceserver.core.MultiStatus;
4552
import org.eclipse.sw360.rest.resourceserver.core.RestControllerHelper;
4653
import org.eclipse.sw360.rest.resourceserver.release.Sw360ReleaseService;
54+
import org.springframework.data.domain.Pageable;
4755
import org.eclipse.sw360.rest.resourceserver.vulnerability.Sw360VulnerabilityService.VulnerabilityOperation;
4856
import org.springframework.beans.factory.annotation.Autowired;
4957
import org.springframework.data.rest.webmvc.BasePathAwareController;
@@ -71,7 +79,9 @@
7179
import java.util.List;
7280
import com.fasterxml.jackson.annotation.JsonInclude;
7381
import com.fasterxml.jackson.databind.ObjectMapper;
82+
import com.google.common.collect.Lists;
7483

84+
import static org.eclipse.sw360.datahandler.common.WrappedException.wrapTException;
7585
import static org.eclipse.sw360.datahandler.permissions.PermissionUtils.makePermission;
7686
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
7787

@@ -91,21 +101,32 @@ public class VulnerabilityController implements RepresentationModelProcessor<Rep
91101
private Sw360ReleaseService releaseService;
92102

93103
@RequestMapping(value = VULNERABILITIES_URL)
94-
public ResponseEntity<CollectionModel<EntityModel<VulnerabilityApiDTO>>> getVulnerabilities() {
104+
public ResponseEntity<CollectionModel<EntityModel<VulnerabilityApiDTO>>> getVulnerabilities(
105+
Pageable pageable,
106+
HttpServletRequest request
107+
) throws TException, URISyntaxException, PaginationParameterException, ResourceClassNotFoundException {
95108
User user = restControllerHelper.getSw360UserFromAuthentication();
96109
List<Vulnerability> vulnerabilities = vulnerabilityService.getVulnerabilities(user);
97-
List<EntityModel<VulnerabilityApiDTO>> vulnerabilityApiDTOResources = new ArrayList<>();
98110

99-
vulnerabilities.forEach(v -> {
111+
PaginationResult<Vulnerability> paginationResult = restControllerHelper.createPaginationResult(request, pageable, vulnerabilities, SW360Constants.TYPE_VULNERABILITY);
112+
List<EntityModel<VulnerabilityApiDTO>> vulnResources = Lists.newArrayList();
113+
for (Vulnerability v: paginationResult.getResources()) {
100114
Set<Release> releaseList = getReleaseRelationsInfo(v, user);
101115
VulnerabilityApiDTO vulnerabilityApiDTO = new VulnerabilityApiDTO();
102116
restControllerHelper.setDataVulApiDTO(vulnerabilityApiDTO, v, releaseList);
103-
vulnerabilityApiDTOResources.add(EntityModel.of(vulnerabilityApiDTO));
117+
vulnResources.add(EntityModel.of(vulnerabilityApiDTO));
118+
}
119+
120+
CollectionModel<EntityModel<VulnerabilityApiDTO>> resources;
121+
if (vulnerabilities.size() == 0) {
122+
resources = restControllerHelper.emptyPageResource(Vulnerability.class, paginationResult);
123+
} else {
124+
resources = restControllerHelper.generatePagesResource(paginationResult, vulnResources);
125+
}
104126

105-
});
127+
HttpStatus status = resources == null ? HttpStatus.NO_CONTENT : HttpStatus.OK;
128+
return new ResponseEntity<>(resources, status);
106129

107-
CollectionModel<EntityModel<VulnerabilityApiDTO>> resources = CollectionModel.of(vulnerabilityApiDTOResources);
108-
return new ResponseEntity<>(resources, HttpStatus.OK);
109130
}
110131

111132
@RequestMapping(VULNERABILITIES_URL + "/{id}")

rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/VulnerabilitySpecTest.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
5858
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
5959
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
60+
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
61+
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
6062
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
6163
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
6264
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -268,17 +270,32 @@ public void should_document_get_vulnerabilities() throws Exception {
268270
String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword);
269271
mockMvc.perform(get("/api/vulnerabilities")
270272
.header("Authorization", "Bearer " + accessToken)
273+
.param("page", "0")
274+
.param("page_entries", "5")
275+
.param("sort", "priority,desc")
271276
.accept(MediaTypes.HAL_JSON))
272277
.andExpect(status().isOk())
273278
.andDo(this.documentationHandler.document(
279+
requestParameters(
280+
parameterWithName("page").description("Page of vulnerabilities"),
281+
parameterWithName("page_entries").description("Amount of vulnerabilities per page"),
282+
parameterWithName("sort").description("Defines order of the vulnerabilities")
283+
),
274284
links(
275-
linkWithRel("curies").description("Curies are used for online documentation")
285+
linkWithRel("curies").description("Curies are used for online documentation"),
286+
linkWithRel("first").description("Link to first page"),
287+
linkWithRel("last").description("Link to last page")
276288
),
277289
responseFields(
278290
subsectionWithPath("_embedded.sw360:vulnerabilityApiDTOes.[]title").description("The title of the vulnerability"),
279291
subsectionWithPath("_embedded.sw360:vulnerabilityApiDTOes.[]externalId").description("The external Id of the vulnerability"),
280292
subsectionWithPath("_embedded.sw360:vulnerabilityApiDTOes").description("An array of <<resources-vulnerabilities, Vulnerabilities resources>>"),
281-
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
293+
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources"),
294+
fieldWithPath("page").description("Additional paging information"),
295+
fieldWithPath("page.size").description("Number of vulnerabilities per page"),
296+
fieldWithPath("page.totalElements").description("Total number of all existing vulnerabilities"),
297+
fieldWithPath("page.totalPages").description("Total number of pages"),
298+
fieldWithPath("page.number").description("Number of the current page")
282299
)));
283300
}
284301

0 commit comments

Comments
 (0)