Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
</developers>

<properties>

<jackson-module-jsonSchema.version>2.15.2</jackson-module-jsonSchema.version>
<gridsuite-dependencies.version>43.0.0</gridsuite-dependencies.version>
<sonar.organization>gridsuite</sonar.organization>
<sonar.projectKey>org.gridsuite:network-map-server</sonar.projectKey>
Expand Down Expand Up @@ -80,6 +80,12 @@

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jsonSchema</artifactId>
<version>${jackson-module-jsonSchema.version}</version>
</dependency>

<!-- project specific dependencies (must be before to have priority during resolution) -->
<dependency><!--TODO remove when springboot version will be updated-->
<groupId>org.junit</groupId>
Expand Down Expand Up @@ -110,6 +116,10 @@

<!-- Compilation dependencies -->
<!-- overrides of imports -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jsonSchema</artifactId>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-network-store-client</artifactId>
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/gridsuite/network/map/NetworkMapApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* 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.network.map;

/**
* @author Hugo Marcellin <hugo.marcelin at rte-france.com>
*/

public final class NetworkMapApi {

private NetworkMapApi() {
}

public static final String API_VERSION = "v1";
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import lombok.AllArgsConstructor;
import org.gridsuite.network.map.dto.*;
import org.gridsuite.network.map.dto.definition.hvdc.HvdcShuntCompensatorsInfos;
import org.gridsuite.network.map.services.NetworkMapService;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.*;

Expand All @@ -28,14 +29,11 @@
* @author Franck Lecuyer <franck.lecuyer at rte-france.com>
*/
@RestController
@RequestMapping(value = "/" + NetworkMapController.API_VERSION + "/")
@Tag(name = "network-map-server")
@RequestMapping(value = "/" + NetworkMapApi.API_VERSION + "/")
@Tag(name = "Network map server")
@ComponentScan(basePackageClasses = NetworkMapService.class)
@AllArgsConstructor
public class NetworkMapController {

public static final String API_VERSION = "v1";

private final NetworkMapService networkMapService;

@PostMapping(value = "/networks/{networkUuid}/elements-ids", produces = APPLICATION_JSON_VALUE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ public OpenAPI createOpenApi() {
.info(new Info()
.title("Network map API")
.description("This is the documentation of network map REST API")
.version(NetworkMapController.API_VERSION));
.version(NetworkMapApi.API_VERSION));
}
}
45 changes: 45 additions & 0 deletions src/main/java/org/gridsuite/network/map/SchemaController.java
Original file line number Diff line number Diff line change
@@ -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.network.map;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.gridsuite.network.map.dto.ElementInfos.InfoType;
import org.gridsuite.network.map.dto.ElementType;
import org.gridsuite.network.map.services.SchemaService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;

@RestController
@RequestMapping(value = "/" + NetworkMapApi.API_VERSION + "/schemas")
@Tag(name = "Network map server - Schemas")
@AllArgsConstructor
public class SchemaController {
public static final String APPLICATION_JSON_SCHEMA_VALUE = "application/schema+json";
private final SchemaService schemaService;

@GetMapping(value = "/{elementType}/{infoType}", produces = APPLICATION_JSON_SCHEMA_VALUE)
@Operation(summary = "Get element schema description")
@ApiResponse(responseCode = "200", description = "Element schema")
public JsonSchema getElementSchema(@Parameter(description = "Element type") @PathVariable(name = "elementType") ElementType elementType,
@Parameter(description = "Info type") @PathVariable(name = "infoType") InfoType infoType) {
try {
return schemaService.getSchema(elementType, infoType);
} catch (final UnsupportedOperationException | JsonMappingException ex) {
throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED, "The view " + infoType + " for " + elementType + " type is not available yet.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* 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.network.map;
package org.gridsuite.network.map.services;

import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* 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.network.map.services;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import org.gridsuite.network.map.dto.ElementInfos.InfoType;
import org.gridsuite.network.map.dto.ElementType;
import org.gridsuite.network.map.dto.definition.battery.BatteryTabInfos;
import org.gridsuite.network.map.dto.definition.branch.BranchTabInfos;
import org.gridsuite.network.map.dto.definition.branch.line.LineTabInfos;
import org.gridsuite.network.map.dto.definition.branch.twowindingstransformer.TwoWindingsTransformerTabInfos;
import org.gridsuite.network.map.dto.definition.bus.BusTabInfos;
import org.gridsuite.network.map.dto.definition.busbarsection.BusBarSectionTabInfos;
import org.gridsuite.network.map.dto.definition.danglingline.DanglingLineTabInfos;
import org.gridsuite.network.map.dto.definition.generator.GeneratorTabInfos;
import org.gridsuite.network.map.dto.definition.hvdc.HvdcTabInfos;
import org.gridsuite.network.map.dto.definition.lccconverterstation.LccConverterStationTabInfos;
import org.gridsuite.network.map.dto.definition.load.LoadTabInfos;
import org.gridsuite.network.map.dto.definition.shuntcompensator.ShuntCompensatorTabInfos;
import org.gridsuite.network.map.dto.definition.staticvarcompensator.StaticVarCompensatorTabInfos;
import org.gridsuite.network.map.dto.definition.substation.SubstationTabInfos;
import org.gridsuite.network.map.dto.definition.threewindingstransformer.ThreeWindingsTransformerTabInfos;
import org.gridsuite.network.map.dto.definition.tieline.TieLineTabInfos;
import org.gridsuite.network.map.dto.definition.voltagelevel.VoltageLevelTabInfos;
import org.gridsuite.network.map.dto.definition.vscconverterstation.VscConverterStationTabInfos;
import org.springframework.stereotype.Service;

@Service
@AllArgsConstructor
public class SchemaService {

private final ObjectMapper objectMapper;

/**
* @apiNote use class instance to be more secure with enum and classes rename/moving/etc with IDE
*/
private static Class<?> getTabInfosClass(final ElementType elementType) {
return switch (elementType) {
case BATTERY -> BatteryTabInfos.class;
case BUS -> BusTabInfos.class;
case BUSBAR_SECTION -> BusBarSectionTabInfos.class;
case DANGLING_LINE -> DanglingLineTabInfos.class;
case GENERATOR -> GeneratorTabInfos.class;
case HVDC_LINE, HVDC_LINE_LCC, HVDC_LINE_VSC -> HvdcTabInfos.class;
case LCC_CONVERTER_STATION -> LccConverterStationTabInfos.class;
case LINE -> LineTabInfos.class;
case LOAD -> LoadTabInfos.class;
case SHUNT_COMPENSATOR -> ShuntCompensatorTabInfos.class;
case STATIC_VAR_COMPENSATOR -> StaticVarCompensatorTabInfos.class;
case SUBSTATION -> SubstationTabInfos.class;
case THREE_WINDINGS_TRANSFORMER -> ThreeWindingsTransformerTabInfos.class;
case TIE_LINE -> TieLineTabInfos.class;
case TWO_WINDINGS_TRANSFORMER -> TwoWindingsTransformerTabInfos.class;
case VOLTAGE_LEVEL -> VoltageLevelTabInfos.class;
case VSC_CONVERTER_STATION -> VscConverterStationTabInfos.class;
case BRANCH -> BranchTabInfos.class;
};
}

public JsonSchema getSchema(@NonNull final ElementType elementType, @NonNull final InfoType infoType) throws JsonMappingException {
if (infoType != InfoType.TAB) {
throw new UnsupportedOperationException("This info type is not currently supported.");
}
JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(objectMapper);
return schemaGen.generateSchema(getTabInfosClass(elementType));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import org.gridsuite.network.map.dto.ElementType;
import org.gridsuite.network.map.dto.InfoTypeParameters;
import org.gridsuite.network.map.services.NetworkMapService;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
Expand Down
70 changes: 70 additions & 0 deletions src/test/java/org/gridsuite/network/map/SchemaControllerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* 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.network.map;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import org.apache.commons.lang3.tuple.Pair;
import org.gridsuite.network.map.dto.ElementInfos.InfoType;
import org.gridsuite.network.map.dto.ElementType;
import org.gridsuite.network.map.services.SchemaService;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.lang.NonNull;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.log;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(SchemaController.class)
class SchemaControllerTest {
@Autowired
private MockMvc mockMvc;

@SpyBean
private SchemaService schemaService;

private static Stream<Arguments> schemaRequestValues() {
final List<Pair<ElementType, InfoType>> cases = new ArrayList<>();
for (ElementType elementType : ElementType.values()) {
for (InfoType infoType : InfoType.values()) {
cases.add(Pair.of(elementType, infoType));
}
}
return cases.stream().map(e1 -> Arguments.of(e1.getKey(), e1.getValue()));
}

@ParameterizedTest(name = "{0} (view {1})")
@MethodSource("schemaRequestValues")
void schemaRequest(@NonNull final ElementType eType, @NonNull final InfoType iType) throws Exception {
ResultActions result = this.mockMvc.perform(get("/v1/schemas/{eType}/{iType}", eType, iType)).andDo(log());
if (iType.equals(InfoType.TAB)) {
JsonSchema schema = schemaService.getSchema(eType, iType);
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(schema);
result.andExpectAll(
status().isOk(),
content().contentType(SchemaController.APPLICATION_JSON_SCHEMA_VALUE),
content().json(json)
);
} else {
result.andExpect(status().isNotImplemented());
}
}
}