-
Notifications
You must be signed in to change notification settings - Fork 0
specific composite controller #781
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
81cf75c
8cbdbe6
fb88ae1
29e720e
9d931a8
58880c9
1ae99f8
395135a
eaea202
f1fa886
c32da69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| /** | ||
| * Copyright (c) 2026, 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.modification.server; | ||
|
|
||
| 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.responses.ApiResponses; | ||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||
| import org.gridsuite.modification.dto.ModificationInfos; | ||
| import org.gridsuite.modification.server.dto.ModificationApplicationContext; | ||
| import org.gridsuite.modification.server.dto.NetworkModificationsResult; | ||
| import org.gridsuite.modification.server.service.NetworkModificationService; | ||
| import org.springframework.data.util.Pair; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.UUID; | ||
| import java.util.concurrent.CompletableFuture; | ||
|
|
||
| /** | ||
| * @author Mathieu Deharbe <mathieu.deharbe at rte-france.com> | ||
| */ | ||
| @RestController | ||
| @RequestMapping(value = "/" + NetworkModificationApi.API_VERSION + "/network-composite-modifications") | ||
| @Tag(name = "network-modification-server - Composite modifications") | ||
| public class CompositeController { | ||
|
|
||
| public enum CompositeModificationAction { | ||
| SPLIT, // the network modifications contained into the composite modifications are extracted and inserted one by one | ||
| INSERT // the composite modifications are fully inserted as composite modifications | ||
| } | ||
|
|
||
| private final NetworkModificationService networkModificationService; | ||
|
|
||
| public CompositeController(NetworkModificationService networkModificationService) { | ||
| this.networkModificationService = networkModificationService; | ||
| } | ||
|
|
||
| @PutMapping(value = "/groups/{groupUuid}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) | ||
| @Operation(summary = "Insert a list of composite network modifications passed in body at the end of a group") | ||
| @ApiResponse(responseCode = "200", description = "The composite modification list has been added to the group.") | ||
| public CompletableFuture<ResponseEntity<NetworkModificationsResult>> insertCompositeModifications( | ||
| @Parameter(description = "updated group UUID, where modifications are inserted") @PathVariable("groupUuid") UUID targetGroupUuid, | ||
| @Parameter(description = "Insertion method", required = true) @RequestParam(value = "action") CompositeModificationAction action, | ||
| @RequestBody Pair<List<Pair<UUID, String>>, List<ModificationApplicationContext>> modificationContextInfos) { | ||
| return switch (action) { | ||
| case SPLIT -> | ||
| networkModificationService.splitCompositeModifications(targetGroupUuid, modificationContextInfos) | ||
| .thenApply(ResponseEntity.ok()::body); | ||
| case INSERT -> | ||
| networkModificationService.insertCompositeModifications( | ||
| targetGroupUuid, | ||
| modificationContextInfos | ||
| ).thenApply(ResponseEntity.ok()::body); | ||
| }; | ||
| } | ||
|
|
||
| @PostMapping(value = "", consumes = MediaType.APPLICATION_JSON_VALUE) | ||
| @Operation(summary = "Create a network composite modification") | ||
| @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The composite modification has been created")}) | ||
| public ResponseEntity<UUID> createNetworkCompositeModification(@RequestBody List<UUID> modificationUuids) { | ||
| return ResponseEntity.ok().body(networkModificationService.createNetworkCompositeModification(modificationUuids)); | ||
| } | ||
|
|
||
| @GetMapping(value = "/network-modifications", produces = MediaType.APPLICATION_JSON_VALUE) | ||
| @Operation(summary = "Get the list of all the network modifications inside a list of composite modifications") | ||
| @ApiResponse(responseCode = "200", description = "List of modifications inside the composite modifications") | ||
| public ResponseEntity<List<ModificationInfos>> getNetworkModificationsFromComposite(@Parameter(description = "Composite modifications uuids list") @RequestParam("uuids") List<UUID> compositeModificationUuids, | ||
| @Parameter(description = "Only metadata") @RequestParam(name = "onlyMetadata", required = false, defaultValue = "true") Boolean onlyMetadata) { | ||
| return ResponseEntity.ok() | ||
| .contentType(MediaType.APPLICATION_JSON) | ||
| .body(networkModificationService.getNetworkModificationsFromComposite(compositeModificationUuids, onlyMetadata) | ||
| ); | ||
| } | ||
|
|
||
| @PostMapping(value = "/duplication", consumes = MediaType.APPLICATION_JSON_VALUE) | ||
| @Operation(summary = "Duplicate some composite modifications") | ||
| @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The duplicated modifications uuids mapped with their source uuid")}) | ||
| public ResponseEntity<Map<UUID, UUID>> duplicateCompositeModifications(@Parameter(description = "source modifications uuids list to duplicate") @RequestBody List<UUID> sourceModificationUuids) { | ||
| return ResponseEntity.ok().body(networkModificationService.duplicateCompositeModifications(sourceModificationUuids)); | ||
| } | ||
|
|
||
| @PutMapping(value = "/{uuid}", consumes = MediaType.APPLICATION_JSON_VALUE) | ||
| @Operation(summary = "Update a network composite modification") | ||
| @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The composite modification has been updated")}) | ||
| public ResponseEntity<Void> updateNetworkCompositeModification(@PathVariable("uuid") UUID compositeModificationUuid, | ||
| @RequestBody List<UUID> modificationUuids) { | ||
| networkModificationService.updateCompositeModification(compositeModificationUuid, modificationUuids); | ||
| return ResponseEntity.ok().build(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,6 @@ | |
| import io.swagger.v3.oas.annotations.responses.ApiResponses; | ||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||
| import org.gridsuite.modification.dto.ModificationInfos; | ||
| import org.gridsuite.modification.dto.ModificationsToCopyInfos; | ||
| import org.gridsuite.modification.server.dto.*; | ||
| import org.gridsuite.modification.server.dto.catalog.LineTypeInfos; | ||
| import org.gridsuite.modification.server.service.LineTypesCatalogService; | ||
|
|
@@ -38,8 +37,6 @@ public class NetworkModificationController { | |
| private enum GroupModificationAction { | ||
| MOVE, | ||
| COPY, | ||
| SPLIT_COMPOSITE, // the network modifications contained into the composite modifications are extracted and inserted one by one | ||
| INSERT_COMPOSITE // the composite modifications are fully inserted as composite modifications | ||
| } | ||
|
|
||
| private final NetworkModificationService networkModificationService; | ||
|
|
@@ -97,24 +94,20 @@ public ResponseEntity<Map<UUID, UUID>> duplicateGroup(@RequestParam("groupUuid") | |
| } | ||
|
|
||
| @PutMapping(value = "/groups/{groupUuid}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) | ||
| @Operation(summary = "For a list of network modifications passed in body, Move them before another one or at the end of the list, or Duplicate them at the end of the list, or Insert them (composite) at the end of the list") | ||
| @Operation(summary = "For a list of network modifications passed in body, Move them before another one or at the end of the list, or Duplicate them at the end of the list") | ||
| @ApiResponse(responseCode = "200", description = "The modification list of the group has been updated.") | ||
| public CompletableFuture<ResponseEntity<NetworkModificationsResult>> handleNetworkModifications( | ||
| @Parameter(description = "updated group UUID, where modifications are pasted") @PathVariable("groupUuid") UUID targetGroupUuid, | ||
| @Parameter(description = "kind of modification", required = true) @RequestParam(value = "action") GroupModificationAction action, | ||
| @Parameter(description = "the modification Uuid to move before (MOVE option, empty means moving at the end)") @RequestParam(value = "before", required = false) UUID beforeModificationUuid, | ||
| @Parameter(description = "origin group UUID, where modifications are copied or cut") @RequestParam(value = "originGroupUuid", required = false) UUID originGroupUuid, | ||
| @Parameter(description = "modifications can be applied (default is true)") @RequestParam(value = "build", required = false, defaultValue = "true") Boolean canApply, | ||
| @RequestBody Pair<List<ModificationsToCopyInfos>, List<ModificationApplicationContext>> modificationContextInfos) { | ||
| List<UUID> modificationsUuids = modificationContextInfos.getFirst().stream().map(ModificationsToCopyInfos::getUuid).toList(); | ||
| @RequestBody Pair<List<UUID>, List<ModificationApplicationContext>> modificationContextInfos) { | ||
|
Comment on lines
+97
to
+105
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This narrows an existing v1 endpoint in a breaking way. The 🤖 Prompt for AI Agents |
||
| return switch (action) { | ||
| case COPY -> | ||
| networkModificationService.duplicateModifications(targetGroupUuid, originGroupUuid, modificationsUuids, modificationContextInfos.getSecond()).thenApply(ResponseEntity.ok()::body); | ||
| case SPLIT_COMPOSITE -> | ||
| networkModificationService.splitCompositeModifications(targetGroupUuid, modificationsUuids, modificationContextInfos.getSecond()).thenApply(ResponseEntity.ok()::body); | ||
| case INSERT_COMPOSITE -> | ||
| networkModificationService.insertCompositeModificationsIntoGroup( | ||
| networkModificationService.duplicateModifications( | ||
| targetGroupUuid, | ||
| originGroupUuid, | ||
| modificationContextInfos.getFirst(), | ||
| modificationContextInfos.getSecond() | ||
| ).thenApply(ResponseEntity.ok()::body); | ||
|
|
@@ -124,7 +117,14 @@ public CompletableFuture<ResponseEntity<NetworkModificationsResult>> handleNetwo | |
| if (sourceGroupUuid.equals(targetGroupUuid)) { | ||
| applyModifications = false; | ||
| } | ||
| yield networkModificationService.moveModifications(targetGroupUuid, sourceGroupUuid, beforeModificationUuid, modificationsUuids, modificationContextInfos.getSecond(), applyModifications).thenApply(ResponseEntity.ok()::body); | ||
| yield networkModificationService.moveModifications( | ||
| targetGroupUuid, | ||
| sourceGroupUuid, | ||
| beforeModificationUuid, | ||
| modificationContextInfos.getFirst(), | ||
| modificationContextInfos.getSecond(), | ||
| applyModifications | ||
| ).thenApply(ResponseEntity.ok()::body); | ||
| } | ||
| }; | ||
| } | ||
|
|
@@ -246,40 +246,6 @@ public ResponseEntity<Void> deleteLineTypesCatalog() { | |
| return ResponseEntity.ok().build(); | ||
| } | ||
|
|
||
| @PostMapping(value = "/network-composite-modifications", consumes = MediaType.APPLICATION_JSON_VALUE) | ||
| @Operation(summary = "Create a network composite modification") | ||
| @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The composite modification has been created")}) | ||
| public ResponseEntity<UUID> createNetworkCompositeModification(@RequestBody List<UUID> modificationUuids) { | ||
| return ResponseEntity.ok().body(networkModificationService.createNetworkCompositeModification(modificationUuids)); | ||
| } | ||
|
|
||
| @GetMapping(value = "/network-composite-modifications/network-modifications", produces = MediaType.APPLICATION_JSON_VALUE) | ||
| @Operation(summary = "Get the list of all the network modifications inside a list of composite modifications") | ||
| @ApiResponse(responseCode = "200", description = "List of modifications inside the composite modifications") | ||
| public ResponseEntity<List<ModificationInfos>> getNetworkModificationsFromComposite(@Parameter(description = "Composite modifications uuids list") @RequestParam("uuids") List<UUID> compositeModificationUuids, | ||
| @Parameter(description = "Only metadata") @RequestParam(name = "onlyMetadata", required = false, defaultValue = "true") Boolean onlyMetadata) { | ||
| return ResponseEntity.ok() | ||
| .contentType(MediaType.APPLICATION_JSON) | ||
| .body(networkModificationService.getNetworkModificationsFromComposite(compositeModificationUuids, onlyMetadata) | ||
| ); | ||
| } | ||
|
|
||
| @PostMapping(value = "/network-composite-modifications/duplication", consumes = MediaType.APPLICATION_JSON_VALUE) | ||
| @Operation(summary = "Duplicate some composite modifications") | ||
| @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The duplicated modifications uuids mapped with their source uuid")}) | ||
| public ResponseEntity<Map<UUID, UUID>> duplicateCompositeModifications(@Parameter(description = "source modifications uuids list to duplicate") @RequestBody List<UUID> sourceModificationUuids) { | ||
| return ResponseEntity.ok().body(networkModificationService.duplicateCompositeModifications(sourceModificationUuids)); | ||
| } | ||
|
|
||
| @PutMapping(value = "/network-composite-modifications/{uuid}", consumes = MediaType.APPLICATION_JSON_VALUE) | ||
| @Operation(summary = "Update a network composite modification") | ||
| @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The composite modification has been updated")}) | ||
| public ResponseEntity<Void> updateNetworkCompositeModification(@PathVariable("uuid") UUID compositeModificationUuid, | ||
| @RequestBody List<UUID> modificationUuids) { | ||
| networkModificationService.updateCompositeModification(compositeModificationUuid, modificationUuids); | ||
| return ResponseEntity.ok().build(); | ||
| } | ||
|
|
||
| @PutMapping(value = "/network-modifications", produces = MediaType.APPLICATION_JSON_VALUE, params = "stashed") | ||
| @Operation(summary = "stash or unstash network modifications") | ||
| @ApiResponse(responseCode = "200", description = "The network modifications were stashed") | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,9 @@ | |
| import org.gridsuite.modification.server.entities.equipment.modification.EquipmentModificationEntity; | ||
| import org.gridsuite.modification.server.entities.tabular.TabularModificationsEntity; | ||
| import org.gridsuite.modification.server.entities.tabular.TabularPropertyEntity; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import org.springframework.data.util.Pair; | ||
| import org.springframework.stereotype.Repository; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
|
|
@@ -64,6 +67,8 @@ public class NetworkModificationRepository { | |
|
|
||
| private static final String MODIFICATION_NOT_FOUND_MESSAGE = "Modification (%s) not found"; | ||
|
|
||
| private static final Logger LOGGER = LoggerFactory.getLogger(NetworkModificationRepository.class); | ||
|
|
||
| public NetworkModificationRepository(ModificationGroupRepository modificationGroupRepository, | ||
| ModificationRepository modificationRepository, | ||
| GeneratorCreationRepository generatorCreationRepository, | ||
|
|
@@ -139,15 +144,6 @@ public UUID createNetworkCompositeModification(@NonNull List<UUID> modificationU | |
| return modificationRepository.save(compositeEntity).getId(); | ||
| } | ||
|
|
||
| public CompositeModificationInfos cloneCompositeModification(@NonNull ModificationsToCopyInfos compositeModification) { | ||
| CompositeModificationInfos newCompositeInfos = CompositeModificationInfos.builder().modifications(List.of()).build(); | ||
| List<ModificationInfos> copiedModifications = getCompositeModificationsInfosNonTransactional(List.of(compositeModification.getUuid())).stream() | ||
| .toList(); | ||
| newCompositeInfos.setModifications(copiedModifications); | ||
| newCompositeInfos.setName(compositeModification.getCompositeName()); | ||
| return newCompositeInfos; | ||
| } | ||
|
|
||
| public void updateCompositeModification(@NonNull UUID compositeUuid, @NonNull List<UUID> modificationUuids) { | ||
| ModificationEntity modificationEntity = modificationRepository.findById(compositeUuid) | ||
| .orElseThrow(() -> new NetworkModificationException(MODIFICATION_NOT_FOUND, String.format(MODIFICATION_NOT_FOUND_MESSAGE, compositeUuid))); | ||
|
|
@@ -789,13 +785,23 @@ public List<ModificationInfos> saveCompositeModifications(@NonNull UUID targetGr | |
| } | ||
|
|
||
| @Transactional | ||
| public List<ModificationInfos> insertCompositeModificationsIntoGroup( | ||
| public List<ModificationInfos> insertCompositeModifications( | ||
| @NonNull UUID targetGroupUuid, | ||
| @NonNull List<ModificationsToCopyInfos> compositeModifications) { | ||
| @NonNull List<Pair<UUID, String>> compositesUuidName) { | ||
| List<UUID> compositeUuids = compositesUuidName.stream().map(Pair::getFirst).toList(); | ||
| List<ModificationInfos> newCompositeModifications = new ArrayList<>(); | ||
| for (ModificationsToCopyInfos compositeModification : compositeModifications) { | ||
| CompositeModificationInfos newCompositeModification = cloneCompositeModification(compositeModification); | ||
| newCompositeModifications.add(newCompositeModification); | ||
| List<ModificationInfos> modificationInfos = getModificationsInfosNonTransactional(compositeUuids); | ||
| // apply the new composite name to the corresponding composite modifications | ||
| for (Pair<UUID, String> compositeUuidName : compositesUuidName) { | ||
| CompositeModificationInfos newCompositeModification = (CompositeModificationInfos) modificationInfos.stream() | ||
| .filter(modif -> modif.getUuid().equals(compositeUuidName.getFirst())) | ||
| .findFirst().orElse(null); | ||
| if (newCompositeModification != null) { | ||
| newCompositeModification.setName(compositeUuidName.getSecond()); | ||
| newCompositeModifications.add(newCompositeModification); | ||
| } else { | ||
| LOGGER.error("Could not find composite modification with uuid {} to apply its name {}", compositeUuidName.getFirst(), compositeUuidName.getSecond()); | ||
| } | ||
Mathieu-Deharbe marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+790
to
+804
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate the fetched DTO type and consume one match per requested insert. Line 796 can throw a 💡 Sketch of a safe lookup- List<ModificationInfos> modificationInfos = getModificationsInfosNonTransactional(compositeUuids);
- // apply the new composite name to the corresponding composite modifications
- for (Pair<UUID, String> compositeUuidName : compositesUuidName) {
- CompositeModificationInfos newCompositeModification = (CompositeModificationInfos) modificationInfos.stream()
- .filter(modif -> modif.getUuid().equals(compositeUuidName.getFirst()))
- .findFirst().orElse(null);
+ Map<UUID, Deque<CompositeModificationInfos>> compositesById = getModificationsInfosNonTransactional(compositeUuids).stream()
+ .map(modif -> {
+ if (!(modif instanceof CompositeModificationInfos composite)) {
+ throw new NetworkModificationException(MODIFICATION_ERROR,
+ String.format("Modification (%s) is not a composite modification", modif.getUuid()));
+ }
+ return composite;
+ })
+ .collect(Collectors.groupingBy(
+ CompositeModificationInfos::getUuid,
+ LinkedHashMap::new,
+ Collectors.toCollection(ArrayDeque::new)
+ ));
+ for (Pair<UUID, String> compositeUuidName : compositesUuidName) {
+ CompositeModificationInfos newCompositeModification = Optional.ofNullable(compositesById.get(compositeUuidName.getFirst()))
+ .map(Deque::pollFirst)
+ .orElse(null);
if (newCompositeModification != null) {
newCompositeModification.setName(compositeUuidName.getSecond());
newCompositeModifications.add(newCompositeModification);🤖 Prompt for AI Agents |
||
| } | ||
| List<ModificationEntity> newEntities = saveModificationInfosNonTransactional(targetGroupUuid, newCompositeModifications); | ||
| return newEntities.stream().map(ModificationEntity::toModificationInfos).toList(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the need of a Pair inbetween List<Pair<UUID, String>> and List I'm not sure I get the logic here, there can be multiple instances of List<Pair<UUID, String> as input ?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure that I understand your question.
Pair<List<Pair<UUID, String>>, List<ModificationApplicationContext>>mans :
List<Pair<UUID, String>: yes there might be several composite modifications inserted simultaneously.List<ModificationApplicationContext>: I didn't look into it much but there are severalModificationApplicationContext, one for each root network in the targetted study.But no there can't be multiple instances of List<Pair<UUID, String> as input.
I don't really know why this data is sent as a pair though. I just kept the previous system from
handleNetworkModifications. It could be separated, but they are in the body so this is probably the reason.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah i just checked it follows what was done in handleNetworkModifications, that said it is getting really confusing the way those data structure get imbricated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. Maybe in the end we will have to use a dto and copy it to study-server...