Skip to content

Commit

Permalink
Update scan and file Rest endpoints to return proper error codes (#123)
Browse files Browse the repository at this point in the history
  • Loading branch information
AHabes authored Oct 5, 2023
1 parent 47d6fbe commit ad27b01
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 65 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.solace.maas.ep.event.management.agent.scanManager.mapper;

import com.solace.maas.ep.event.management.agent.scanManager.model.DataCollectionFileBO;
import com.solace.maas.ep.event.management.agent.scanManager.model.DataCollectionFileDTO;
import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.Mapper;

@Mapper(componentModel = "spring", collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
public interface DataCollectionFileMapper {
DataCollectionFileBO map(DataCollectionFileDTO dto);

DataCollectionFileDTO map(DataCollectionFileBO bo);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.solace.maas.ep.event.management.agent.scanManager.model;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class DataCollectionFileDTO {
private String id;

private String path;

private boolean purged;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.solace.maas.ep.event.management.agent.scanManager.rest;

import com.solace.maas.ep.event.management.agent.scanManager.model.DataCollectionFileDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestParam;

public interface DataCollectionFileController {

@Operation(
summary = "Retrieves the details about scan files",
description = "Use this API to retrieve the details about the files generated by a scan request.",
responses = {
@ApiResponse(
responseCode = "200",
description = "Details about the scan files have been retrieved successfully."
)
}
)
ResponseEntity<Page<DataCollectionFileDTO>> list(@RequestParam("scanId") String scanId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
package com.solace.maas.ep.event.management.agent.scanManager.rest;

import com.solace.maas.ep.event.management.agent.constants.RestEndpoint;
import com.solace.maas.ep.event.management.agent.scanManager.model.DataCollectionFileBO;
import com.solace.maas.ep.event.management.agent.scanManager.mapper.DataCollectionFileMapper;
import com.solace.maas.ep.event.management.agent.scanManager.model.DataCollectionFileDTO;
import com.solace.maas.ep.event.management.agent.service.DataCollectionFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.CrossOrigin;

@Slf4j
@Validated
@CrossOrigin
@RestController
@RequestMapping(RestEndpoint.DATA_COLLECTION_FILE_URL)
public class DataCollectionFileControllerImpl {
private final DataCollectionFileService dataCollectionFileService;
public class DataCollectionFileControllerImpl implements DataCollectionFileController {
private final DataCollectionFileService dataCollectionFileService;
private final DataCollectionFileMapper dataCollectionFileMapper;

public DataCollectionFileControllerImpl(DataCollectionFileService dataCollectionFileService) {
public DataCollectionFileControllerImpl(DataCollectionFileService dataCollectionFileService,
DataCollectionFileMapper dataCollectionFileMapper) {
this.dataCollectionFileService = dataCollectionFileService;
this.dataCollectionFileMapper = dataCollectionFileMapper;
}

@Override
@GetMapping("/query")
public ResponseEntity<Page<DataCollectionFileBO>> list(@RequestParam("scanId") String scanId,
Pageable pageable) {
return ResponseEntity.ok().body(dataCollectionFileService.findByScanId(scanId, pageable));
public ResponseEntity<Page<DataCollectionFileDTO>> list(@RequestParam("scanId") String scanId, Pageable pageable) {
return ResponseEntity.ok().body(dataCollectionFileService.findByScanId(scanId, pageable)
.map(dataCollectionFileMapper::map));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
import com.solace.maas.ep.common.model.ScanRequestDTO;
import com.solace.maas.ep.event.management.agent.config.eventPortal.EventPortalProperties;
import com.solace.maas.ep.event.management.agent.constants.RestEndpoint;
import com.solace.maas.ep.event.management.agent.plugin.route.exceptions.ClientException;
import com.solace.maas.ep.event.management.agent.scanManager.ScanManager;
import com.solace.maas.ep.event.management.agent.scanManager.mapper.ScanRequestMapper;
import com.solace.maas.ep.event.management.agent.scanManager.model.ScanRequestBO;
import com.solace.maas.ep.event.management.agent.util.IDGenerator;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.CrossOrigin;
Expand All @@ -19,7 +20,6 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import jakarta.validation.Valid;
import java.util.List;

@Slf4j
Expand Down Expand Up @@ -47,34 +47,30 @@ public EMAControllerImpl(ScanRequestMapper scanRequestMapper, ScanManager scanMa
@PostMapping(value = "/{resourceId}/scan")
public ResponseEntity<String> scan(@PathVariable(value = "resourceId") String messagingServiceId,
@RequestBody @Valid ScanRequestDTO body) {
try {
ScanRequestBO scanRequestBO = scanRequestMapper.map(body);
scanRequestBO.setMessagingServiceId(messagingServiceId);
scanRequestBO.setScanId(idGenerator.generateRandomUniqueId());

boolean isEMAStandalone = eventPortalProperties.getGateway().getMessaging().isStandalone();
List<String> destinations = scanRequestBO.getDestinations();

if (!isEMAStandalone) {
throw new RestErrorHandler.RestException("Scan requests via REST endpoint could not be initiated in connected mode.");
}
ScanRequestBO scanRequestBO = scanRequestMapper.map(body);
scanRequestBO.setMessagingServiceId(messagingServiceId);
scanRequestBO.setScanId(idGenerator.generateRandomUniqueId());

if (destinations.contains("EVENT_PORTAL")) {
throw new RestErrorHandler.RestException("Scan data could not be streamed to EP in standalone mode.");
}
boolean isEMAStandalone = eventPortalProperties.getGateway().getMessaging().isStandalone();
List<String> destinations = scanRequestBO.getDestinations();

log.info("Scan request [{}]: Received, request details: {}", scanRequestBO.getScanId(), scanRequestBO);

String scanId = scanManager.scan(scanRequestBO);
if (!isEMAStandalone) {
throw ClientException.builder()
.message("Scan requests via REST endpoint could not be initiated in connected mode.")
.build();
}
if (destinations.contains("EVENT_PORTAL")) {
throw ClientException.builder()
.message("Scan data could not be streamed to the Event Portal in standalone mode.")
.build();
}

String message = String.format("Scan request [%s]: Scan started.", scanId);
log.info(message);
log.info("Scan request [{}]: Received, request details: {}", scanRequestBO.getScanId(), scanRequestBO);

return ResponseEntity.ok().body(message);
String scanId = scanManager.scan(scanRequestBO);
String message = String.format("Scan request [%s]: Scan started.", scanId);
log.info(message);

} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(e.getMessage());
}
return ResponseEntity.ok().body(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
package com.solace.maas.ep.event.management.agent.scanManager.rest;

import com.solace.maas.ep.common.model.EventErrorDTO;
import com.solace.maas.ep.event.management.agent.plugin.route.exceptions.ClientException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice
public class RestErrorHandler {

@ExceptionHandler({RestException.class})
@ExceptionHandler(ClientException.class)
@ResponseBody
public ResponseEntity<EventErrorDTO> handleRestException(RestException restException) {
public ResponseEntity<EventErrorDTO> handleRestException(ClientException restException) {
EventErrorDTO eventErrorDTO = new EventErrorDTO(restException.getMessage());
return new ResponseEntity<>(eventErrorDTO, HttpStatus.BAD_REQUEST);
}

@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public static class RestException extends RuntimeException {
public RestException(String message) {
super(message);
}

public RestException(String message, Exception cause) {
super(message, cause);
}
@ExceptionHandler(PropertyReferenceException.class)
@ResponseBody
public ResponseEntity<EventErrorDTO> handlePropertyReferenceException(PropertyReferenceException exception) {
EventErrorDTO eventErrorDTO = new EventErrorDTO(exception.getMessage());
return new ResponseEntity<>(eventErrorDTO, HttpStatus.BAD_REQUEST);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
import com.solace.maas.ep.event.management.agent.config.eventPortal.EventPortalProperties;
import com.solace.maas.ep.event.management.agent.config.eventPortal.GatewayMessagingProperties;
import com.solace.maas.ep.event.management.agent.config.eventPortal.GatewayProperties;
import com.solace.maas.ep.event.management.agent.plugin.route.exceptions.ClientException;
import com.solace.maas.ep.event.management.agent.scanManager.ScanManager;
import com.solace.maas.ep.event.management.agent.scanManager.mapper.ScanRequestMapper;
import com.solace.maas.ep.event.management.agent.scanManager.model.ScanRequestBO;
import com.solace.maas.ep.event.management.agent.util.IDGenerator;
import org.junit.Rule;
import org.junit.jupiter.api.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus;
Expand All @@ -22,14 +21,14 @@

import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@ActiveProfiles("TEST")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = TestConfig.class)
public class EMAControllerTest {
@Rule
public ExpectedException exception = ExpectedException.none();

@Autowired
private ScanRequestMapper scanRequestMapper;
Expand Down Expand Up @@ -57,16 +56,12 @@ public void testEMAControllerInConnectedMode() {
when(scanManager.scan(scanRequestBO))
.thenReturn("scanId");

EMAController controller =
new EMAControllerImpl(scanRequestMapper, scanManager, idGenerator, eventPortalProperties);

ResponseEntity<String> reply = controller.scan("id", scanRequestDTO);
EMAController controller = new EMAControllerImpl(scanRequestMapper, scanManager, idGenerator, eventPortalProperties);

// Scan requests via REST endpoints are prevented in connected mode, e.g., standalone=false
assertThat(reply.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
assertThat(reply.getBody()).contains("Scan requests via REST endpoint could not be initiated in connected mode.");
ClientException thrown = assertThrows(ClientException.class, () -> controller.scan("id", scanRequestDTO));

exception.expect(Exception.class);
assertTrue(thrown.getMessage().contains("Scan requests via REST endpoint could not be initiated in connected mode."));
}

@Test
Expand All @@ -93,13 +88,9 @@ public void testEMAControllerInStandAloneModeWithEventPortalDestination() {

EMAController controller = new EMAControllerImpl(scanRequestMapper, scanManager, idGenerator, eventPortalProperties);

ResponseEntity<String> reply =
controller.scan("id", scanRequestDTO);

assertThat(reply.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
assertThat(reply.getBody()).contains("Scan data could not be streamed to EP in standalone mode.");
ClientException thrown = assertThrows(ClientException.class, () -> controller.scan("id", scanRequestDTO));

exception.expect(Exception.class);
assertThat(thrown.getMessage()).contains("Scan data could not be streamed to the Event Portal in standalone mode.");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.solace.maas.ep.event.management.agent.plugin.route.exceptions;

import com.solace.maas.ep.event.management.agent.plugin.jacoco.ExcludeFromJacocoGeneratedReport;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;

Expand All @@ -10,9 +11,10 @@
@EqualsAndHashCode(callSuper = true)
@Data
@ExcludeFromJacocoGeneratedReport
@Builder
public class ClientException extends RuntimeException {
private String message;
private Map<String, List<Exception>> exceptionStore;
private final String message;
private final Map<String, List<Exception>> exceptionStore;

ClientException(final String message, final Map<String, List<Exception>> validationDetails) {
super();
Expand Down

0 comments on commit ad27b01

Please sign in to comment.