Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@
public class NetworkModificationController {

private enum GroupModificationAction {
MOVE, COPY, INSERT
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 composote modifications
}

private final NetworkModificationService networkModificationService;
Expand Down Expand Up @@ -89,17 +92,26 @@ 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")
@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<UUID>, List<ModificationApplicationContext>> modificationContextInfos) {
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,
@Parameter(description = "composite modification name") @RequestParam(value = "compositeName", required = false, defaultValue = "My Composite") String compositeName,
@RequestBody Pair<List<UUID>, List<ModificationApplicationContext>> modificationContextInfos) {
return switch (action) {
case COPY ->
networkModificationService.duplicateModifications(targetGroupUuid, originGroupUuid, modificationContextInfos.getFirst(), modificationContextInfos.getSecond()).thenApply(ResponseEntity.ok()::body);
case INSERT ->
networkModificationService.insertCompositeModifications(targetGroupUuid, modificationContextInfos.getFirst(), modificationContextInfos.getSecond()).thenApply(ResponseEntity.ok()::body);
case SPLIT_COMPOSITE ->
networkModificationService.splitCompositeModifications(targetGroupUuid, modificationContextInfos.getFirst(), modificationContextInfos.getSecond()).thenApply(ResponseEntity.ok()::body);
case INSERT_COMPOSITE ->
networkModificationService.insertCompositeModificationIntoGroup(
targetGroupUuid,
modificationContextInfos.getFirst().getFirst(),
modificationContextInfos.getSecond().getFirst(),
compositeName
).thenApply(ResponseEntity.ok()::body);
case MOVE -> {
UUID sourceGroupUuid = originGroupUuid == null ? targetGroupUuid : originGroupUuid;
boolean applyModifications = canApply;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
@Table(name = "composite_modification")
public class CompositeModificationEntity extends ModificationEntity {

@Column(name = "composite_name")
private String compositeName;

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(
name = "compositeModificationSubModifications",
Expand All @@ -44,6 +47,7 @@ public CompositeModificationEntity(@NonNull CompositeModificationInfos composite
public CompositeModificationInfos toModificationInfos() {
List<ModificationInfos> modificationsInfos = modifications.stream().map(ModificationEntity::toModificationInfos).toList();
return CompositeModificationInfos.builder()
.compositeName(getCompositeName())
.activated(getActivated())
.description(getDescription())
.date(getDate())
Expand All @@ -56,6 +60,7 @@ public CompositeModificationInfos toModificationInfos() {
// when we go back to an empty list, dont use addAll() on the list because JPA could start
// @OrderColumn to 1 instead of 0
private void assignAttributes(CompositeModificationInfos compositeModificationInfos) {
this.setCompositeName(compositeModificationInfos.getCompositeName());
modifications.clear();
modifications = compositeModificationInfos.getModifications().stream()
.map(ModificationEntity::fromDTO)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,15 @@ private List<ModificationEntity> saveModificationInfosNonTransactional(UUID grou
return saveModificationsNonTransactional(groupUuid, entities);
}

public UUID createNetworkCompositeModification(@NonNull List<UUID> modificationUuids) {
public UUID createNetworkCompositeModification(@NonNull List<UUID> modificationUuids, String name) {
CompositeModificationInfos compositeInfos = CompositeModificationInfos.builder().modifications(List.of()).build();
CompositeModificationEntity compositeEntity = (CompositeModificationEntity) ModificationEntity.fromDTO(compositeInfos);
List<ModificationEntity> copyEntities = modificationRepository.findAllByIdIn(modificationUuids).stream()
.map(this::toModificationsInfosOptimizedForTabular)
.map(ModificationEntity::fromDTO)
.toList();
compositeEntity.setModifications(copyEntities);
compositeEntity.setCompositeName(name);
return modificationRepository.save(compositeEntity).getId();
}

Expand Down Expand Up @@ -765,4 +766,18 @@ public List<ModificationInfos> saveCompositeModifications(@NonNull UUID targetGr
// We can't return modificationInfos directly because it wouldn't have the IDs coming from the new saved entities
return newEntities.stream().map(ModificationEntity::toModificationInfos).toList();
}

@Transactional
public CompositeModificationInfos insertCompositeModificationIntoGroup(
@NonNull UUID targetGroupUuid,
@NonNull UUID compositeModificationUuid,
@NonNull String compositeName) {
CompositeModificationEntity oldCompositeModification = (CompositeModificationEntity) getModificationEntity(compositeModificationUuid);
List<UUID> oldModificationsUuids = oldCompositeModification.getModifications().stream().map(ModificationEntity::getId).collect(Collectors.toList());

UUID newCompositeModificationUuid = createNetworkCompositeModification(oldModificationsUuids, compositeName);
CompositeModificationEntity newCompositeModification = (CompositeModificationEntity) getModificationEntity(newCompositeModificationUuid);
saveModificationInfosNonTransactional(targetGroupUuid, List.of(newCompositeModification.toModificationInfos()));
return newCompositeModification.toModificationInfos();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.commons.lang3.StringUtils;
import org.gridsuite.filter.AbstractFilter;
import org.gridsuite.modification.NetworkModificationException;
import org.gridsuite.modification.dto.CompositeModificationInfos;
import org.gridsuite.modification.dto.GenerationDispatchInfos;
import org.gridsuite.modification.dto.ModificationInfos;
import org.gridsuite.modification.server.NetworkModificationServerException;
Expand Down Expand Up @@ -397,16 +398,30 @@ public CompletableFuture<NetworkModificationsResult> duplicateModifications(@Non
new NetworkModificationsResult(ids, result));
}

public CompletableFuture<NetworkModificationsResult> insertCompositeModifications(@NonNull UUID targetGroupUuid, @NonNull List<UUID> modificationsUuids, @NonNull List<ModificationApplicationContext> applicationContexts) {
/**
* all their network modifications are extracted from the composite modifications and inserted into the group
* @param modificationsUuids uuids of the composite modifications
*/
public CompletableFuture<NetworkModificationsResult> splitCompositeModifications(@NonNull UUID targetGroupUuid, @NonNull List<UUID> modificationsUuids, @NonNull List<ModificationApplicationContext> applicationContexts) {
List<ModificationInfos> modifications = networkModificationRepository.saveCompositeModifications(targetGroupUuid, modificationsUuids);
List<UUID> ids = modifications.stream().map(ModificationInfos::getUuid).toList();
return applyModifications(targetGroupUuid, modifications, applicationContexts).thenApply(result ->
new NetworkModificationsResult(ids, result));
}

public CompletableFuture<NetworkModificationsResult> insertCompositeModificationIntoGroup(
@NonNull UUID targetGroupUuid,
@NonNull UUID compositeModificationUuid,
@NonNull ModificationApplicationContext applicationContext,
@NonNull String compositeName) {
CompositeModificationInfos modification = networkModificationRepository.insertCompositeModificationIntoGroup(targetGroupUuid, compositeModificationUuid, compositeName);
return applyModifications(targetGroupUuid, List.of(modification), List.of(applicationContext)).thenApply(result ->
new NetworkModificationsResult(List.of(modification.getUuid()), result));
}

@Transactional
public UUID createNetworkCompositeModification(@NonNull List<UUID> modificationUuids) {
return networkModificationRepository.createNetworkCompositeModification(modificationUuids);
return networkModificationRepository.createNetworkCompositeModification(modificationUuids, null);
}

public Map<UUID, UUID> duplicateCompositeModifications(List<UUID> sourceModificationUuids) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet author="deharbemat (generated)" id="1770384121049-15">
<addColumn tableName="composite_modification">
<column name="composite_name" type="varchar(255)"/>
</addColumn>
</changeSet>
</databaseChangeLog>
3 changes: 3 additions & 0 deletions src/main/resources/db/changelog/db.changelog-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -453,3 +453,6 @@ databaseChangeLog:
- include:
file: changesets/changelog_20251215T152152Z.xml
relativeToChangelogFile: true
- include:
file: changesets/changelog_20260206T132143Z.xml
relativeToChangelogFile: true
Original file line number Diff line number Diff line change
Expand Up @@ -845,14 +845,11 @@ void testNetworkCompositeModification() throws Exception {
mvcResult = mockMvc.perform(get(URI_GET_COMPOSITE_NETWORK_MODIF_CONTENT + "/network-modifications?uuids={id}&onlyMetadata=false", compositeModificationUuid))
.andExpect(status().isOk()).andReturn();
compositeModificationContent = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { });
assertEquals("open", ((EquipmentAttributeModificationInfos) compositeModificationContent.get(0)).getEquipmentAttributeName());
assertEquals(Boolean.TRUE, ((EquipmentAttributeModificationInfos) compositeModificationContent.get(0)).getEquipmentAttributeValue());
assertEquals(IdentifiableType.SWITCH, ((EquipmentAttributeModificationInfos) compositeModificationContent.get(0)).getEquipmentType());
assertEquals("v1b1", ((EquipmentAttributeModificationInfos) compositeModificationContent.get(0)).getEquipmentId());
checkCompositeModificationContent(compositeModificationContent);

// Insert the composite modification in the group
String bodyJson = getJsonBody(List.of(compositeModificationUuid), NetworkCreation.VARIANT_ID);
mvcResult = runRequestAsync(mockMvc, put("/v1/groups/" + TEST_GROUP_ID + "?action=INSERT").content(bodyJson).contentType(MediaType.APPLICATION_JSON), status().isOk());
final String bodyJson = getJsonBody(List.of(compositeModificationUuid), NetworkCreation.VARIANT_ID);
mvcResult = runRequestAsync(mockMvc, put("/v1/groups/" + TEST_GROUP_ID + "?action=SPLIT_COMPOSITE").content(bodyJson).contentType(MediaType.APPLICATION_JSON), status().isOk());

assertApplicationStatusOK(mvcResult);

Expand All @@ -861,6 +858,27 @@ void testNetworkCompositeModification() throws Exception {
List<UUID> newModificationUuidList = newModificationList.stream().map(ModificationInfos::getUuid).toList();
assertEquals(modificationUuids.get(0), newModificationUuidList.get(0));
assertThat(modificationList.get(0)).recursivelyEquals(newModificationList.get(modificationsNumber));

// insert the same composite modification inside the same group but this time as a complete composite, not split into regular network modifications
mvcResult = runRequestAsync(
mockMvc,
put("/v1/groups/" + TEST_GROUP_ID + "?action=INSERT_COMPOSITE&compositeName='random name'")
.content(bodyJson).contentType(MediaType.APPLICATION_JSON), status().isOk()
);
assertApplicationStatusOK(mvcResult);
newModificationList = modificationRepository.getModifications(TEST_GROUP_ID, false, true);
assertEquals(modificationsNumber * 2 + 1, newModificationList.size());
CompositeModificationInfos insertedComposite = (CompositeModificationInfos) newModificationList.stream().filter(modificationInfos ->
modificationInfos.getType().equals(COMPOSITE_MODIFICATION)).findFirst().orElseThrow();
assertNotNull(insertedComposite);
checkCompositeModificationContent(insertedComposite.getModifications());
}

private static void checkCompositeModificationContent(List<ModificationInfos> compositeModificationContent) {
assertEquals("open", ((EquipmentAttributeModificationInfos) compositeModificationContent.getFirst()).getEquipmentAttributeName());
assertEquals(Boolean.TRUE, ((EquipmentAttributeModificationInfos) compositeModificationContent.getFirst()).getEquipmentAttributeValue());
assertEquals(IdentifiableType.SWITCH, ((EquipmentAttributeModificationInfos) compositeModificationContent.getFirst()).getEquipmentType());
assertEquals("v1b1", ((EquipmentAttributeModificationInfos) compositeModificationContent.getFirst()).getEquipmentId());
}

/**
Expand Down Expand Up @@ -903,13 +921,10 @@ void testNetworkCompositeModificationOld() throws Exception {
mvcResult = mockMvc.perform(get(URI_GET_COMPOSITE_NETWORK_MODIF_CONTENT + "/network-modifications?uuids={id}&onlyMetadata=false", compositeModificationUuid))
.andExpect(status().isOk()).andReturn();
compositeModificationContent = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { });
assertEquals("open", ((EquipmentAttributeModificationInfos) compositeModificationContent.get(0)).getEquipmentAttributeName());
assertEquals(Boolean.TRUE, ((EquipmentAttributeModificationInfos) compositeModificationContent.get(0)).getEquipmentAttributeValue());
assertEquals(IdentifiableType.SWITCH, ((EquipmentAttributeModificationInfos) compositeModificationContent.get(0)).getEquipmentType());
assertEquals("v1b1", ((EquipmentAttributeModificationInfos) compositeModificationContent.get(0)).getEquipmentId());
checkCompositeModificationContent(compositeModificationContent);
String bodyJson = getJsonBody(List.of(compositeModificationUuid), NetworkCreation.VARIANT_ID);
// Insert the composite modification in the group
mvcResult = runRequestAsync(mockMvc, put("/v1/groups/" + TEST_GROUP_ID + "?action=INSERT").content(bodyJson).contentType(MediaType.APPLICATION_JSON), status().isOk());
mvcResult = runRequestAsync(mockMvc, put("/v1/groups/" + TEST_GROUP_ID + "?action=SPLIT_COMPOSITE").content(bodyJson).contentType(MediaType.APPLICATION_JSON), status().isOk());

assertApplicationStatusOK(mvcResult);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,10 +304,10 @@ void testInsertCompositeModifications() {
((NetworkImpl) networkInfos.getNetwork()).getListeners().clear();

/*
Insert as composite this modification to group 2, variant 2
Split this composite and insert the contained modifications to group 2, variant 2
*/
UUID groupUuid2 = UUID.randomUUID();
NetworkModificationsResult modificationsResult = networkModificationService.insertCompositeModifications(
NetworkModificationsResult modificationsResult = networkModificationService.splitCompositeModifications(
groupUuid2,
List.of(compositeUuid),
List.of(new ModificationApplicationContext(networkInfos.getNetworkUuuid(), variant2, UUID.randomUUID(), UUID.randomUUID()))
Expand Down
Loading