diff --git a/pom.xml b/pom.xml index 25e43eac..edc9a78c 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,10 @@ 5.0.0-alpha.14 gridsuite org.gridsuite:security-analysis-server + + 1.7.0 + 1.34.0 + 1.15.0 @@ -87,6 +91,24 @@ + + + com.powsybl + powsybl-ws-commons + ${powsybl-ws-commons.version} + + + + org.gridsuite + gridsuite-computation + ${gridsuite-computation.version} + + + + org.gridsuite + gridsuite-filter + ${gridsuite-filter.version} + com.squareup.okhttp3 diff --git a/src/main/java/org/gridsuite/securityanalysis/server/PropertyServerNameProvider.java b/src/main/java/org/gridsuite/securityanalysis/server/PropertyServerNameProvider.java new file mode 100644 index 00000000..62bd340d --- /dev/null +++ b/src/main/java/org/gridsuite/securityanalysis/server/PropertyServerNameProvider.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2025, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.securityanalysis.server; + +import com.powsybl.ws.commons.error.ServerNameProvider; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * @author Hugo Marcellin + */ +@Component +public class PropertyServerNameProvider implements ServerNameProvider { + + private final String name; + + public PropertyServerNameProvider(@Value("${spring.application.name:security-analysis-server}") String name) { + this.name = name; + } + + @Override + public String serverName() { + return name; + } +} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/RestResponseEntityExceptionHandler.java b/src/main/java/org/gridsuite/securityanalysis/server/RestResponseEntityExceptionHandler.java deleted file mode 100644 index e4a957f7..00000000 --- a/src/main/java/org/gridsuite/securityanalysis/server/RestResponseEntityExceptionHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2023, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.gridsuite.securityanalysis.server; - -import org.gridsuite.computation.ComputationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -/** - * @author Kevin Le Saulnier - */ - -@ControllerAdvice -public class RestResponseEntityExceptionHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(RestResponseEntityExceptionHandler.class); - - @ExceptionHandler(ComputationException.class) - protected ResponseEntity handleStudyException(ComputationException exception) { - if (LOGGER.isErrorEnabled()) { - LOGGER.error(exception.getMessage()); - } - switch (exception.getExceptionType()) { - case RESULT_NOT_FOUND, PARAMETERS_NOT_FOUND: - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(exception.getExceptionType()); - case INVALID_FILTER_FORMAT, INVALID_FILTER, INVALID_SORT_FORMAT: - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception.getExceptionType()); - default: - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(exception.getExceptionType()); - } - } -} diff --git a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisApplication.java b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisApplication.java index 0f73a9bb..c266f515 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisApplication.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/SecurityAnalysisApplication.java @@ -7,6 +7,7 @@ package org.gridsuite.securityanalysis.server; import com.powsybl.network.store.client.NetworkStoreService; +import org.gridsuite.computation.error.ComputationExceptionHandler; import org.gridsuite.computation.service.NotificationService; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -15,7 +16,7 @@ * @author Geoffroy Jamgotchian */ @SuppressWarnings("checkstyle:HideUtilityClassConstructor") -@SpringBootApplication(scanBasePackageClasses = { SecurityAnalysisApplication.class, NetworkStoreService.class, NotificationService.class }) +@SpringBootApplication(scanBasePackageClasses = {SecurityAnalysisApplication.class, NetworkStoreService.class, NotificationService.class, ComputationExceptionHandler.class}) public class SecurityAnalysisApplication { public static void main(String[] args) { SpringApplication.run(SecurityAnalysisApplication.class, args); diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/FilterService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/FilterService.java index 7379187a..352671c7 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/FilterService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/FilterService.java @@ -15,6 +15,7 @@ import org.gridsuite.securityanalysis.server.entities.ContingencyEntity; import org.gridsuite.securityanalysis.server.entities.SubjectLimitViolationEntity; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.stereotype.Service; import java.util.List; @@ -27,10 +28,10 @@ @Service public class FilterService extends AbstractFilterService { - public FilterService( - NetworkStoreService networkStoreService, - @Value("${gridsuite.services.filter-server.base-uri:http://filter-server/}") String filterServerBaseUri) { - super(networkStoreService, filterServerBaseUri); + public FilterService(RestTemplateBuilder restTemplateBuilder, + NetworkStoreService networkStoreService, + @Value("${gridsuite.services.filter-server.base-uri:http://filter-server/}") String filterServerBaseUri) { + super(restTemplateBuilder, networkStoreService, filterServerBaseUri); } public Optional getResourceFilterN(@NonNull UUID networkUuid, @NonNull String variantId, @NonNull GlobalFilter globalFilter) { diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/LimitReductionService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/LimitReductionService.java index 5dde8c0a..2d8a2f5d 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/LimitReductionService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/LimitReductionService.java @@ -6,7 +6,7 @@ */ package org.gridsuite.securityanalysis.server.service; -import org.gridsuite.computation.ComputationException; +import org.gridsuite.computation.error.ComputationException; import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.Range; @@ -19,6 +19,8 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import static org.gridsuite.computation.error.ComputationBusinessErrorCode.LIMIT_REDUCTION_CONFIG_ERROR; + @Setter @Getter @Service @@ -64,41 +66,41 @@ private List getLimitReductionsByD private void assertValidConfig(List> values) { if (voltageLevels.isEmpty()) { - throw new ComputationException(ComputationException.Type.LIMIT_REDUCTION_CONFIG_ERROR, "No configuration for voltage levels"); + throw new ComputationException(LIMIT_REDUCTION_CONFIG_ERROR, "No configuration for voltage levels"); } if (limitDurations.isEmpty()) { - throw new ComputationException(ComputationException.Type.LIMIT_REDUCTION_CONFIG_ERROR, "No configuration for limit durations"); + throw new ComputationException(LIMIT_REDUCTION_CONFIG_ERROR, "No configuration for limit durations"); } if (values.isEmpty() || values.get(0).isEmpty()) { - throw new ComputationException(ComputationException.Type.LIMIT_REDUCTION_CONFIG_ERROR, "No values provided"); + throw new ComputationException(LIMIT_REDUCTION_CONFIG_ERROR, "No values provided"); } int nbValuesByVl = values.get(0).size(); if (values.stream().anyMatch(valuesByVl -> valuesByVl.size() != nbValuesByVl)) { - throw new ComputationException(ComputationException.Type.LIMIT_REDUCTION_CONFIG_ERROR, "Number of values for a voltage level is incorrect"); + throw new ComputationException(LIMIT_REDUCTION_CONFIG_ERROR, "Number of values for a voltage level is incorrect"); } if (voltageLevels.size() < values.size()) { - throw new ComputationException(ComputationException.Type.LIMIT_REDUCTION_CONFIG_ERROR, "Too many values provided for voltage levels"); + throw new ComputationException(LIMIT_REDUCTION_CONFIG_ERROR, "Too many values provided for voltage levels"); } if (voltageLevels.size() > values.size()) { - throw new ComputationException(ComputationException.Type.LIMIT_REDUCTION_CONFIG_ERROR, "Not enough values provided for voltage levels"); + throw new ComputationException(LIMIT_REDUCTION_CONFIG_ERROR, "Not enough values provided for voltage levels"); } if (limitDurations.size() < nbValuesByVl - 1) { - throw new ComputationException(ComputationException.Type.LIMIT_REDUCTION_CONFIG_ERROR, "Too many values provided for limit durations"); + throw new ComputationException(LIMIT_REDUCTION_CONFIG_ERROR, "Too many values provided for limit durations"); } if (limitDurations.size() > nbValuesByVl - 1) { - throw new ComputationException(ComputationException.Type.LIMIT_REDUCTION_CONFIG_ERROR, "Not enough values provided for limit durations"); + throw new ComputationException(LIMIT_REDUCTION_CONFIG_ERROR, "Not enough values provided for limit durations"); } values.forEach(valuesByVl -> { if (valuesByVl.stream().anyMatch(v -> !Range.of(0.0, 1.0).contains(v))) { - throw new ComputationException(ComputationException.Type.LIMIT_REDUCTION_CONFIG_ERROR, "Value not between 0 and 1"); + throw new ComputationException(LIMIT_REDUCTION_CONFIG_ERROR, "Value not between 0 and 1"); } }); } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java index 8d82cd9a..d2f16aef 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisParametersService.java @@ -7,7 +7,7 @@ package org.gridsuite.securityanalysis.server.service; import com.powsybl.security.SecurityAnalysisParameters; -import org.gridsuite.computation.ComputationException; +import org.gridsuite.computation.error.ComputationException; import org.gridsuite.computation.dto.ReportInfos; import lombok.NonNull; import org.gridsuite.securityanalysis.server.dto.*; @@ -19,7 +19,8 @@ import java.util.*; -import static org.gridsuite.computation.ComputationException.Type.PARAMETERS_NOT_FOUND; +import static org.gridsuite.computation.error.ComputationBusinessErrorCode.PARAMETERS_NOT_FOUND; + /** * @author Abdelsalem HEDHILI @@ -159,7 +160,7 @@ public Optional duplicateParameters(UUID sourceParametersUuid) { @Transactional public UUID updateParameters(UUID parametersUuid, SecurityAnalysisParametersValues parametersInfos) { - SecurityAnalysisParametersEntity securityAnalysisParametersEntity = securityAnalysisParametersRepository.findById(parametersUuid).orElseThrow(() -> new ComputationException(PARAMETERS_NOT_FOUND)); + SecurityAnalysisParametersEntity securityAnalysisParametersEntity = securityAnalysisParametersRepository.findById(parametersUuid).orElseThrow(() -> new ComputationException(PARAMETERS_NOT_FOUND, "Could not find provided parameters")); //if the parameters is null it means it's a reset to defaultValues, but we need to keep the provider because it's updated separately if (parametersInfos == null) { securityAnalysisParametersEntity.update(getDefaultSecurityAnalysisParametersValues(securityAnalysisParametersEntity.getProvider())); diff --git a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java index 3be710fc..cfdbdd60 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/service/SecurityAnalysisResultService.java @@ -12,7 +12,7 @@ import com.powsybl.security.LimitViolationType; import com.powsybl.security.SecurityAnalysisResult; import lombok.Getter; -import org.gridsuite.computation.ComputationException; +import org.gridsuite.computation.error.ComputationException; import org.gridsuite.computation.dto.GlobalFilter; import org.gridsuite.computation.dto.ResourceFilterDTO; import org.gridsuite.computation.service.AbstractComputationResultService; @@ -36,6 +36,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import static org.gridsuite.computation.error.ComputationBusinessErrorCode.INVALID_SORT_FORMAT; +import static org.gridsuite.computation.error.ComputationBusinessErrorCode.RESULT_NOT_FOUND; import static org.gridsuite.computation.utils.FilterUtils.fromStringFiltersToDTO; import static org.gridsuite.computation.utils.FilterUtils.fromStringGlobalFiltersToDTO; @@ -225,13 +227,13 @@ private void assertNmKSubjectLimitViolationsSortAllowed(Sort sort) { private void assertSortAllowed(Sort sort, List allowedSortProperties) { if (!sort.stream().allMatch(order -> allowedSortProperties.contains(order.getProperty()))) { - throw new ComputationException(ComputationException.Type.INVALID_SORT_FORMAT); + throw new ComputationException(INVALID_SORT_FORMAT, "Invalid sort format"); } } public void assertResultExists(UUID resultUuid) { if (securityAnalysisResultRepository.findById(resultUuid).isEmpty()) { - throw new ComputationException(ComputationException.Type.RESULT_NOT_FOUND); + throw new ComputationException(RESULT_NOT_FOUND, "Result not found"); } } diff --git a/src/main/java/org/gridsuite/securityanalysis/server/util/CsvExportUtils.java b/src/main/java/org/gridsuite/securityanalysis/server/util/CsvExportUtils.java index e6a346be..5f38cd95 100644 --- a/src/main/java/org/gridsuite/securityanalysis/server/util/CsvExportUtils.java +++ b/src/main/java/org/gridsuite/securityanalysis/server/util/CsvExportUtils.java @@ -1,6 +1,5 @@ package org.gridsuite.securityanalysis.server.util; -import org.gridsuite.computation.ComputationException; import com.univocity.parsers.csv.CsvFormat; import com.univocity.parsers.csv.CsvWriter; import com.univocity.parsers.csv.CsvWriterSettings; @@ -8,6 +7,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; @@ -42,7 +42,7 @@ public static byte[] csvRowsToZippedCsv(List headers, String language, L csvWriter.close(); return outputStream.toByteArray(); } catch (IOException e) { - throw new ComputationException(ComputationException.Type.FILE_EXPORT_ERROR); + throw new UncheckedIOException("Error occured during data csv export", e); } } diff --git a/src/test/java/org/gridsuite/securityanalysis/server/FindContingenciesTest.java b/src/test/java/org/gridsuite/securityanalysis/server/FindContingenciesTest.java index 54aee0f9..4335755a 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/FindContingenciesTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/FindContingenciesTest.java @@ -12,7 +12,7 @@ import com.powsybl.network.store.iidm.impl.NetworkFactoryImpl; import com.powsybl.security.LimitViolationType; import org.gridsuite.computation.dto.ResourceFilterDTO; -import org.gridsuite.computation.ComputationException; +import org.gridsuite.computation.error.ComputationException; import org.gridsuite.computation.utils.SpecificationUtils; import org.gridsuite.securityanalysis.server.dto.ContingencyResultDTO; import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisStatus; @@ -44,6 +44,7 @@ import static com.vladmihalcea.sql.SQLStatementCountValidator.assertSelectCount; import static com.vladmihalcea.sql.SQLStatementCountValidator.reset; import static org.assertj.core.api.Assertions.assertThat; +import static org.gridsuite.computation.error.ComputationBusinessErrorCode.INVALID_SORT_FORMAT; import static org.gridsuite.securityanalysis.server.SecurityAnalysisProviderMock.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -253,8 +254,8 @@ private static Stream provideEdgeCasesFilters() { private static Stream provideForbiddenSort() { return Stream.of( - Arguments.of(List.of(), PageRequest.of(0, 30, Sort.by(Sort.Direction.ASC, "limitType")), new ComputationException(ComputationException.Type.INVALID_SORT_FORMAT)), - Arguments.of(List.of(), PageRequest.of(0, 30, Sort.by(Sort.Direction.DESC, "side")), new ComputationException(ComputationException.Type.INVALID_SORT_FORMAT)) + Arguments.of(List.of(), PageRequest.of(0, 30, Sort.by(Sort.Direction.ASC, "limitType")), new ComputationException(INVALID_SORT_FORMAT, "Invalid sort format")), + Arguments.of(List.of(), PageRequest.of(0, 30, Sort.by(Sort.Direction.DESC, "side")), new ComputationException(INVALID_SORT_FORMAT, "Invalid sort format")) ); } diff --git a/src/test/java/org/gridsuite/securityanalysis/server/FindSubjectLimitViolationsTest.java b/src/test/java/org/gridsuite/securityanalysis/server/FindSubjectLimitViolationsTest.java index 4d395d77..2e60b3a4 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/FindSubjectLimitViolationsTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/FindSubjectLimitViolationsTest.java @@ -12,7 +12,7 @@ import com.powsybl.network.store.iidm.impl.NetworkFactoryImpl; import com.powsybl.security.LimitViolationType; import org.gridsuite.computation.dto.ResourceFilterDTO; -import org.gridsuite.computation.ComputationException; +import org.gridsuite.computation.error.ComputationException; import org.gridsuite.computation.utils.SpecificationUtils; import org.gridsuite.securityanalysis.server.dto.ContingencyLimitViolationDTO; import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisStatus; @@ -41,6 +41,7 @@ import static com.vladmihalcea.sql.SQLStatementCountValidator.assertSelectCount; import static com.vladmihalcea.sql.SQLStatementCountValidator.reset; import static org.assertj.core.api.Assertions.assertThat; +import static org.gridsuite.computation.error.ComputationBusinessErrorCode.INVALID_SORT_FORMAT; import static org.gridsuite.securityanalysis.server.SecurityAnalysisProviderMock.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -216,8 +217,8 @@ private static Stream provideEachColumnFilter() { private static Stream provideForbiddenSort() { return Stream.of( - Arguments.of(List.of(), PageRequest.of(0, 30, Sort.by(Sort.Direction.ASC, "contingencyId")), new ComputationException(ComputationException.Type.INVALID_SORT_FORMAT)), - Arguments.of(List.of(), PageRequest.of(0, 30, Sort.by(Sort.Direction.DESC, "side")), new ComputationException(ComputationException.Type.INVALID_SORT_FORMAT)) + Arguments.of(List.of(), PageRequest.of(0, 30, Sort.by(Sort.Direction.ASC, "contingencyId")), new ComputationException(INVALID_SORT_FORMAT, "Invalid sort format")), + Arguments.of(List.of(), PageRequest.of(0, 30, Sort.by(Sort.Direction.DESC, "side")), new ComputationException(INVALID_SORT_FORMAT, "Invalid sort format")) ); } diff --git a/src/test/java/org/gridsuite/securityanalysis/server/PropertyServerNameProviderTest.java b/src/test/java/org/gridsuite/securityanalysis/server/PropertyServerNameProviderTest.java new file mode 100644 index 00000000..086d78fa --- /dev/null +++ b/src/test/java/org/gridsuite/securityanalysis/server/PropertyServerNameProviderTest.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2025, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.securityanalysis.server; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Hugo Marcellin + */ +class PropertyServerNameProviderTest { + + @Test + void returnsProvidedName() { + PropertyServerNameProvider provider = new PropertyServerNameProvider("custom-server"); + assertThat(provider.serverName()).isEqualTo("custom-server"); + } +} diff --git a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java index 03a43a9c..e6a429d0 100644 --- a/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java +++ b/src/test/java/org/gridsuite/securityanalysis/server/SecurityAnalysisParametersControllerTest.java @@ -8,7 +8,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import org.gridsuite.computation.ComputationException; +import org.gridsuite.computation.error.ComputationException; import org.gridsuite.securityanalysis.server.dto.LimitReductionsByVoltageLevel; import org.gridsuite.securityanalysis.server.dto.SecurityAnalysisParametersValues; import org.gridsuite.securityanalysis.server.entities.SecurityAnalysisParametersEntity; @@ -30,7 +30,7 @@ import java.util.UUID; import static com.powsybl.network.store.model.NetworkStoreApi.VERSION; -import static org.gridsuite.computation.ComputationException.Type.PARAMETERS_NOT_FOUND; +import static org.gridsuite.computation.error.ComputationBusinessErrorCode.PARAMETERS_NOT_FOUND; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; @@ -181,7 +181,7 @@ void securityAnalysisParametersUpdateTest() throws Exception { .contentType(MediaType.APPLICATION_JSON)) .andExpectAll( status().isNotFound(), - result -> assertTrue(result.getResponse().getContentAsString().contains(PARAMETERS_NOT_FOUND.name()))); + result -> assertTrue(result.getResponse().getContentAsString().contains(PARAMETERS_NOT_FOUND.value()))); //create default parameters and return id mvcResult = mockMvc.perform(post("/" + VERSION + "/parameters/default"))