diff --git a/pom.xml b/pom.xml
index 0c187c2..3ed2b06 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,6 +56,10 @@
org.gridsuite.voltageinit.server
gridsuite
org.gridsuite:voltage-init-server
+
+ 1.7.0
+ 1.34.0
+ 1.15.0
@@ -90,6 +94,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/voltageinit/server/PropertyServerNameProvider.java b/src/main/java/org/gridsuite/voltageinit/server/PropertyServerNameProvider.java
new file mode 100644
index 0000000..5a40230
--- /dev/null
+++ b/src/main/java/org/gridsuite/voltageinit/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.voltageinit.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:voltage-init-server}") String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String serverName() {
+ return name;
+ }
+}
diff --git a/src/main/java/org/gridsuite/voltageinit/server/VoltageInitApplication.java b/src/main/java/org/gridsuite/voltageinit/server/VoltageInitApplication.java
index a203e8b..28adb89 100644
--- a/src/main/java/org/gridsuite/voltageinit/server/VoltageInitApplication.java
+++ b/src/main/java/org/gridsuite/voltageinit/server/VoltageInitApplication.java
@@ -7,6 +7,7 @@
package org.gridsuite.voltageinit.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 Etienne Homer
*/
@SuppressWarnings("checkstyle:HideUtilityClassConstructor")
-@SpringBootApplication(scanBasePackageClasses = { VoltageInitApplication.class, NetworkStoreService.class, NotificationService.class })
+@SpringBootApplication(scanBasePackageClasses = {VoltageInitApplication.class, NetworkStoreService.class, NotificationService.class, ComputationExceptionHandler.class})
public class VoltageInitApplication {
public static void main(String[] args) {
SpringApplication.run(VoltageInitApplication.class, args);
diff --git a/src/main/java/org/gridsuite/voltageinit/server/error/VoltageInitBusinessErrorCode.java b/src/main/java/org/gridsuite/voltageinit/server/error/VoltageInitBusinessErrorCode.java
new file mode 100644
index 0000000..d7b5b1f
--- /dev/null
+++ b/src/main/java/org/gridsuite/voltageinit/server/error/VoltageInitBusinessErrorCode.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2017-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/.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+package org.gridsuite.voltageinit.server.error;
+
+import com.powsybl.ws.commons.error.BusinessErrorCode;
+
+/**
+ * @author Hugo Marcellin
+ */
+public enum VoltageInitBusinessErrorCode implements BusinessErrorCode {
+ MISSING_FILTER("voltageInit.missingFilter");
+
+ private final String code;
+
+ VoltageInitBusinessErrorCode(String code) {
+ this.code = code;
+ }
+
+ public String value() {
+ return code;
+ }
+}
diff --git a/src/main/java/org/gridsuite/voltageinit/server/error/VoltageInitException.java b/src/main/java/org/gridsuite/voltageinit/server/error/VoltageInitException.java
index 408e6ea..30c5300 100644
--- a/src/main/java/org/gridsuite/voltageinit/server/error/VoltageInitException.java
+++ b/src/main/java/org/gridsuite/voltageinit/server/error/VoltageInitException.java
@@ -6,14 +6,25 @@
*/
package org.gridsuite.voltageinit.server.error;
+import com.powsybl.ws.commons.error.AbstractBusinessException;
+import lombok.NonNull;
+
import java.util.Objects;
/**
* @author Mohamed Ben-rejeb {@literal }
*/
-public class VoltageInitException extends RuntimeException {
+public class VoltageInitException extends AbstractBusinessException {
+
+ private final VoltageInitBusinessErrorCode errorCode;
- public VoltageInitException(String message) {
+ public VoltageInitException(VoltageInitBusinessErrorCode errorCode, String message) {
super(Objects.requireNonNull(message, "message must not be null"));
+ this.errorCode = Objects.requireNonNull(errorCode, "errorCode must not be null");
+ }
+
+ @Override
+ public @NonNull VoltageInitBusinessErrorCode getBusinessErrorCode() {
+ return errorCode;
}
}
diff --git a/src/main/java/org/gridsuite/voltageinit/server/error/VoltageInitExceptionHandler.java b/src/main/java/org/gridsuite/voltageinit/server/error/VoltageInitExceptionHandler.java
new file mode 100644
index 0000000..209deb7
--- /dev/null
+++ b/src/main/java/org/gridsuite/voltageinit/server/error/VoltageInitExceptionHandler.java
@@ -0,0 +1,45 @@
+/**
+ * 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.voltageinit.server.error;
+
+import com.powsybl.ws.commons.error.AbstractBusinessExceptionHandler;
+import com.powsybl.ws.commons.error.PowsyblWsProblemDetail;
+import com.powsybl.ws.commons.error.ServerNameProvider;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.NonNull;
+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 Hugo Marcellin
+ */
+@ControllerAdvice
+public class VoltageInitExceptionHandler extends AbstractBusinessExceptionHandler {
+ protected VoltageInitExceptionHandler(ServerNameProvider serverNameProvider) {
+ super(serverNameProvider);
+ }
+
+ @Override
+ protected @NonNull VoltageInitBusinessErrorCode getBusinessCode(VoltageInitException e) {
+ return e.getBusinessErrorCode();
+ }
+
+ @Override
+ protected HttpStatus mapStatus(VoltageInitBusinessErrorCode businessErrorCode) {
+ return switch (businessErrorCode) {
+ case MISSING_FILTER -> HttpStatus.INTERNAL_SERVER_ERROR;
+ };
+ }
+
+ @ExceptionHandler(VoltageInitException.class)
+ protected ResponseEntity handleVoltageInitException(
+ VoltageInitException exception, HttpServletRequest request) {
+ return super.handleDomainException(exception, request);
+ }
+}
diff --git a/src/main/java/org/gridsuite/voltageinit/server/service/parameters/FilterService.java b/src/main/java/org/gridsuite/voltageinit/server/service/parameters/FilterService.java
index 01b0ae5..baa7c6d 100644
--- a/src/main/java/org/gridsuite/voltageinit/server/service/parameters/FilterService.java
+++ b/src/main/java/org/gridsuite/voltageinit/server/service/parameters/FilterService.java
@@ -15,8 +15,10 @@
import org.gridsuite.filter.AbstractFilter;
import org.gridsuite.filter.utils.EquipmentType;
import org.gridsuite.voltageinit.server.dto.parameters.FilterEquipments;
+import org.gridsuite.voltageinit.server.error.VoltageInitBusinessErrorCode;
import org.gridsuite.voltageinit.server.error.VoltageInitException;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
@@ -45,9 +47,10 @@ public class FilterService extends AbstractFilterService {
public static final String FILTERS_NOT_FOUND = "Filters not found";
- public FilterService(NetworkStoreService networkStoreService,
+ public FilterService(RestTemplateBuilder restTemplateBuilder,
+ NetworkStoreService networkStoreService,
@Value("${gridsuite.services.filter-server.base-uri:http://filter-server/}") String filterServerBaseUri) {
- super(networkStoreService, filterServerBaseUri);
+ super(restTemplateBuilder, networkStoreService, filterServerBaseUri);
}
public List exportFilters(List filtersUuids, UUID networkUuid, String variantId) {
@@ -85,7 +88,7 @@ public void ensureFiltersExist(Map filterNamesByUuid) {
.filter(filterId -> !validFilters.contains(filterId))
.toList();
if (!missingFilters.isEmpty()) {
- throw new VoltageInitException(buildMissingFiltersMessage(missingFilters, filterNamesByUuid));
+ throw new VoltageInitException(VoltageInitBusinessErrorCode.MISSING_FILTER, buildMissingFiltersMessage(missingFilters, filterNamesByUuid));
}
}
diff --git a/src/test/java/org/gridsuite/voltageinit/server/PropertyServerNameProviderTest.java b/src/test/java/org/gridsuite/voltageinit/server/PropertyServerNameProviderTest.java
new file mode 100644
index 0000000..b932fc3
--- /dev/null
+++ b/src/test/java/org/gridsuite/voltageinit/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.voltageinit.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/voltageinit/server/VoltageInitBusinessErrorCodeTest.java b/src/test/java/org/gridsuite/voltageinit/server/VoltageInitBusinessErrorCodeTest.java
new file mode 100644
index 0000000..5d667fb
--- /dev/null
+++ b/src/test/java/org/gridsuite/voltageinit/server/VoltageInitBusinessErrorCodeTest.java
@@ -0,0 +1,24 @@
+/**
+ * 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.voltageinit.server;
+
+import org.gridsuite.voltageinit.server.error.VoltageInitBusinessErrorCode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+import static org.gridsuite.voltageinit.utils.assertions.Assertions.assertThat;
+
+/**
+ * @author Hugo Marcellin
+ */
+class VoltageInitBusinessErrorCodeTest {
+ @ParameterizedTest
+ @EnumSource(VoltageInitBusinessErrorCode.class)
+ void valueMatchesEnumName(VoltageInitBusinessErrorCode code) {
+ assertThat(code.value()).startsWith("voltageInit.");
+ }
+}
diff --git a/src/test/java/org/gridsuite/voltageinit/server/error/VoltageInitExceptionHandlerTest.java b/src/test/java/org/gridsuite/voltageinit/server/error/VoltageInitExceptionHandlerTest.java
new file mode 100644
index 0000000..cc8aadf
--- /dev/null
+++ b/src/test/java/org/gridsuite/voltageinit/server/error/VoltageInitExceptionHandlerTest.java
@@ -0,0 +1,42 @@
+/**
+ * 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.voltageinit.server.error;
+
+import com.powsybl.ws.commons.error.PowsyblWsProblemDetail;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.mock.web.MockHttpServletRequest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.gridsuite.voltageinit.server.error.VoltageInitBusinessErrorCode.MISSING_FILTER;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Hugo Marcellin
+ */
+class VoltageInitExceptionHandlerTest {
+
+ private VoltageInitExceptionHandler handler;
+
+ @BeforeEach
+ void setUp() {
+ handler = new VoltageInitExceptionHandler(() -> "voltageInit");
+ }
+
+ @Test
+ void mapsInteralErrorBusinessErrorToStatus() {
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/results-endpoint/uuid");
+ VoltageInitException exception = new VoltageInitException(MISSING_FILTER, "Bus out of voltage");
+ ResponseEntity response = handler.handleVoltageInitException(exception, request);
+
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
+ assertThat(response.getBody()).isNotNull();
+ assertEquals("voltageInit.missingFilter", response.getBody().getBusinessErrorCode());
+ }
+}
diff --git a/src/test/java/org/gridsuite/voltageinit/server/service/parameters/FilterServiceTest.java b/src/test/java/org/gridsuite/voltageinit/server/service/parameters/FilterServiceTest.java
index 322def0..18ef856 100644
--- a/src/test/java/org/gridsuite/voltageinit/server/service/parameters/FilterServiceTest.java
+++ b/src/test/java/org/gridsuite/voltageinit/server/service/parameters/FilterServiceTest.java
@@ -14,6 +14,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
+import org.springframework.boot.web.client.RestTemplateBuilder;
import java.util.List;
import java.util.Optional;
@@ -38,7 +39,7 @@ class FilterServiceTest {
@BeforeEach
void setUp() {
- filterService = spy(new FilterService(Mockito.mock(NetworkStoreService.class), "http://filter-server/"));
+ filterService = spy(new FilterService(Mockito.mock(RestTemplateBuilder.class), Mockito.mock(NetworkStoreService.class), "http://filter-server/"));
}
@Test
diff --git a/src/test/java/org/gridsuite/voltageinit/server/service/parameters/ParametersTest.java b/src/test/java/org/gridsuite/voltageinit/server/service/parameters/ParametersTest.java
index 187c9df..e488a7e 100644
--- a/src/test/java/org/gridsuite/voltageinit/server/service/parameters/ParametersTest.java
+++ b/src/test/java/org/gridsuite/voltageinit/server/service/parameters/ParametersTest.java
@@ -27,6 +27,7 @@
import org.gridsuite.voltageinit.server.entities.parameters.FilterEquipmentsEmbeddable;
import org.gridsuite.voltageinit.server.entities.parameters.VoltageInitParametersEntity;
import org.gridsuite.voltageinit.server.entities.parameters.VoltageLimitEntity;
+import org.gridsuite.voltageinit.server.error.VoltageInitBusinessErrorCode;
import org.gridsuite.voltageinit.server.error.VoltageInitException;
import org.gridsuite.voltageinit.server.service.VoltageInitRunContext;
import org.gridsuite.voltageinit.server.util.EquipmentsSelectionType;
@@ -211,7 +212,7 @@ void buildOpenReacParametersThrowsWhenFilterMissing() {
.withResourceBundles("i18n.reports")
.withMessageTemplate(COMPUTATION_TYPE).build());
- Mockito.doThrow(new VoltageInitException(FilterService.FILTERS_NOT_FOUND + " [" + FILTER_1 + "]"))
+ Mockito.doThrow(new VoltageInitException(VoltageInitBusinessErrorCode.MISSING_FILTER, FilterService.FILTERS_NOT_FOUND + " [" + FILTER_1 + "]"))
.when(filterService)
.ensureFiltersExist(Mockito.anyMap());