From 3b7ef0051fd58f6a1fd90e98c4b73d1c30b4123a Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Thu, 30 Apr 2026 17:14:17 +0200 Subject: [PATCH 1/7] draft merge some modifications into a new composite Signed-off-by: Mathieu DEHARBE --- .../server/controller/StudyController.java | 20 ++++++++++++ .../service/NetworkModificationService.java | 18 +++++++++++ .../study/server/service/StudyService.java | 31 +++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index c0e5bd0f8..ee44d5ca3 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -690,6 +690,26 @@ public ResponseEntity moveOrCopyModifications(@PathVariable("studyUuid") U return ResponseEntity.ok().build(); } + @PutMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/composite-modification", produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "For a list of network modifications passed in body, merge them into a composite modification") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The composite modification has been created.")}) + public ResponseEntity mergeModificationsIntoComposite( + @PathVariable("studyUuid") UUID studyUuid, + @PathVariable("nodeUuid") UUID nodeUuid, + @Parameter(description = "uuids of the merged modifications") @RequestParam(name = "modificationsUuids") List modificationsUuids, + @RequestHeader(HEADER_USER_ID) String userId) { + studyService.assertIsStudyAndNodeExist(studyUuid, nodeUuid); + studyService.assertCanUpdateNodeInStudy(studyUuid, nodeUuid); + studyService.assertNoBlockedNodeInStudy(studyUuid, nodeUuid); + studyService.invalidateNodeTreeWithLF(studyUuid, nodeUuid); + try { + studyService.mergeModificationsIntoComposite(studyUuid, nodeUuid, modificationsUuids, userId); + } finally { + studyService.unblockNodeTree(studyUuid, nodeUuid); + } + return ResponseEntity.ok().build(); + } + /** * @param modificationsToInsert pair of the composite uuid and its name */ diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java index 852a378dc..24781eff9 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java @@ -300,6 +300,24 @@ public NetworkModificationsResult insertCompositeModifications(UUID groupUuid, ).getBody(); } + public NetworkModificationsResult mergeModificationsIntoComposite( + UUID groupUuid, + List modificationsUuids, + List modificationContexts) { + var path = UriComponentsBuilder.fromPath(COMPOSITE_PATH + GROUP_PATH + DELIMITER + "composite-modification"); // TODO : comment différencier de l'autre endpoint ?? + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity, List>> httpEntity = new HttpEntity<>(Pair.of(modificationsUuids, modificationContexts), headers); + + return restTemplate.exchange( + getNetworkModificationServerURI(false) + path.buildAndExpand(groupUuid).toUriString(), + HttpMethod.PUT, + httpEntity, + NetworkModificationsResult.class + ).getBody(); + } + private NetworkModificationsResult handleModifications(UUID groupUuid, UUID originGroupUuid, ModificationsActionType action, Pair, List> modificationContextInfos) { var path = UriComponentsBuilder.fromPath(GROUP_PATH) diff --git a/src/main/java/org/gridsuite/study/server/service/StudyService.java b/src/main/java/org/gridsuite/study/server/service/StudyService.java index 5527d3ce9..bb3d5d7d6 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -2437,6 +2437,37 @@ public void duplicateNetworkModifications( userId); } + @Transactional + public void mergeModificationsIntoComposite( + UUID targetStudyUuid, + UUID targetNodeUuid, + List modificationsUuids, + String userId) { + List childrenUuids = networkModificationTreeService.getChildrenUuids(targetNodeUuid); + notificationService.emitStartModificationEquipmentNotification(targetStudyUuid, targetNodeUuid, childrenUuids, NotificationService.MODIFICATIONS_UPDATING_IN_PROGRESS); + try { + checkStudyContainsNode(targetStudyUuid, targetNodeUuid); + + List studyRootNetworkEntities = getStudyRootNetworks(targetStudyUuid); + UUID groupUuid = networkModificationTreeService.getModificationGroupUuid(targetNodeUuid); + + List modificationApplicationContexts = studyRootNetworkEntities.stream() + .map(rootNetworkEntity -> rootNetworkNodeInfoService.getNetworkModificationApplicationContext(rootNetworkEntity.getId(), targetNodeUuid, rootNetworkEntity.getNetworkUuid())) + .toList(); + + NetworkModificationsResult networkModificationResults = networkModificationService.mergeModificationsIntoComposite( + groupUuid, + modificationsUuids, + modificationApplicationContexts + ); + + sendImpactNotifications(targetStudyUuid, targetNodeUuid, networkModificationResults, studyRootNetworkEntities); + } finally { + notificationService.emitEndModificationEquipmentNotification(targetStudyUuid, targetNodeUuid, childrenUuids); + } + notificationService.emitElementUpdated(targetStudyUuid, userId); + } + @Transactional public void insertCompositeNetworkModifications( UUID targetStudyUuid, From 6bace98f428e52bec581d655048157581bf00f61 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Tue, 5 May 2026 15:24:01 +0200 Subject: [PATCH 2/7] PostMapping Signed-off-by: Mathieu DEHARBE --- .../study/server/controller/StudyController.java | 8 ++++---- .../study/server/service/NetworkModificationService.java | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index ee44d5ca3..a036e71af 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -690,13 +690,13 @@ public ResponseEntity moveOrCopyModifications(@PathVariable("studyUuid") U return ResponseEntity.ok().build(); } - @PutMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/composite-modification", produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "For a list of network modifications passed in body, merge them into a composite modification") + @PostMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/composite-modification", produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "For a list of network modifications passed in body, merge them into a new composite modification") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The composite modification has been created.")}) - public ResponseEntity mergeModificationsIntoComposite( + public ResponseEntity mergeModificationsIntoNewComposite( @PathVariable("studyUuid") UUID studyUuid, @PathVariable("nodeUuid") UUID nodeUuid, - @Parameter(description = "uuids of the merged modifications") @RequestParam(name = "modificationsUuids") List modificationsUuids, + @RequestBody List modificationsUuids, @RequestHeader(HEADER_USER_ID) String userId) { studyService.assertIsStudyAndNodeExist(studyUuid, nodeUuid); studyService.assertCanUpdateNodeInStudy(studyUuid, nodeUuid); diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java index 24781eff9..dc78fe94d 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java @@ -308,11 +308,14 @@ public NetworkModificationsResult mergeModificationsIntoComposite( HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity, List>> httpEntity = new HttpEntity<>(Pair.of(modificationsUuids, modificationContexts), headers); + HttpEntity, List>> httpEntity = new HttpEntity<>( + Pair.of(modificationsUuids, modificationContexts), + headers + ); return restTemplate.exchange( getNetworkModificationServerURI(false) + path.buildAndExpand(groupUuid).toUriString(), - HttpMethod.PUT, + HttpMethod.POST, httpEntity, NetworkModificationsResult.class ).getBody(); From 15bbd40804eab0a95664e43ca7099cde856510b8 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Fri, 15 May 2026 12:13:04 +0200 Subject: [PATCH 3/7] transmit composite uuid Signed-off-by: Mathieu DEHARBE --- .../study/server/controller/StudyController.java | 7 ++++--- .../study/server/service/NetworkModificationService.java | 7 ++++--- .../org/gridsuite/study/server/service/StudyService.java | 9 ++++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index c5c9168c2..a71cfa6a7 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -694,7 +694,7 @@ public ResponseEntity moveOrCopyModifications(@PathVariable("studyUuid") U @PostMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/composite-modification", produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "For a list of network modifications passed in body, merge them into a new composite modification") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The composite modification has been created.")}) - public ResponseEntity mergeModificationsIntoNewComposite( + public ResponseEntity mergeModificationsIntoNewComposite( @PathVariable("studyUuid") UUID studyUuid, @PathVariable("nodeUuid") UUID nodeUuid, @RequestBody List modificationsUuids, @@ -703,12 +703,13 @@ public ResponseEntity mergeModificationsIntoNewComposite( studyService.assertCanUpdateNodeInStudy(studyUuid, nodeUuid); studyService.assertNoBlockedNodeInStudy(studyUuid, nodeUuid); studyService.invalidateNodeTreeWithLF(studyUuid, nodeUuid); + UUID newCompositeUuid; try { - studyService.mergeModificationsIntoComposite(studyUuid, nodeUuid, modificationsUuids, userId); + newCompositeUuid = studyService.mergeModificationsIntoComposite(studyUuid, nodeUuid, modificationsUuids, userId); } finally { studyService.unblockNodeTree(studyUuid, nodeUuid); } - return ResponseEntity.ok().build(); + return ResponseEntity.ok().body(newCompositeUuid); } /** diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java index 2270f4cda..fbef5ade5 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java @@ -300,11 +300,12 @@ public NetworkModificationsResult insertCompositeModifications(UUID groupUuid, ).getBody(); } - public NetworkModificationsResult mergeModificationsIntoComposite( + public UUID mergeModificationsIntoComposite( UUID groupUuid, List modificationsUuids, List modificationContexts) { - var path = UriComponentsBuilder.fromPath(COMPOSITE_PATH + GROUP_PATH + DELIMITER + "composite-modification"); // TODO : comment différencier de l'autre endpoint ?? + // TODO : comment différencier de l'autre endpoint ?? + var path = UriComponentsBuilder.fromPath(COMPOSITE_PATH + GROUP_PATH + DELIMITER + "composite-modification"); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); @@ -317,7 +318,7 @@ public NetworkModificationsResult mergeModificationsIntoComposite( getNetworkModificationServerURI(false) + path.buildAndExpand(groupUuid).toUriString(), HttpMethod.POST, httpEntity, - NetworkModificationsResult.class + UUID.class ).getBody(); } diff --git a/src/main/java/org/gridsuite/study/server/service/StudyService.java b/src/main/java/org/gridsuite/study/server/service/StudyService.java index d36ea0560..d2e429254 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -2447,11 +2447,12 @@ public void duplicateNetworkModifications( } @Transactional - public void mergeModificationsIntoComposite( + public UUID mergeModificationsIntoComposite( UUID targetStudyUuid, UUID targetNodeUuid, List modificationsUuids, String userId) { + UUID newCompositeUuid; List childrenUuids = networkModificationTreeService.getChildrenUuids(targetNodeUuid); notificationService.emitStartModificationEquipmentNotification(targetStudyUuid, targetNodeUuid, childrenUuids, NotificationService.MODIFICATIONS_UPDATING_IN_PROGRESS); try { @@ -2464,17 +2465,19 @@ public void mergeModificationsIntoComposite( .map(rootNetworkEntity -> rootNetworkNodeInfoService.getNetworkModificationApplicationContext(rootNetworkEntity.getId(), targetNodeUuid, rootNetworkEntity.getNetworkUuid())) .toList(); - NetworkModificationsResult networkModificationResults = networkModificationService.mergeModificationsIntoComposite( + newCompositeUuid = networkModificationService.mergeModificationsIntoComposite( groupUuid, modificationsUuids, modificationApplicationContexts ); - sendImpactNotifications(targetStudyUuid, targetNodeUuid, networkModificationResults, studyRootNetworkEntities); + // TODO : envoyer une notification pour tout le noeud ?? Mais il est déjà déréalisé + // sendImpactNotifications(targetStudyUuid, targetNodeUuid, networkModificationResults, studyRootNetworkEntities); } finally { notificationService.emitEndModificationEquipmentNotification(targetStudyUuid, targetNodeUuid, childrenUuids); } notificationService.emitElementUpdated(targetStudyUuid, userId); + return newCompositeUuid; } @Transactional From 1e7338f5e4ec05948d6ff7887920f45563e368fc Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Fri, 15 May 2026 17:48:11 +0200 Subject: [PATCH 4/7] invalidate nodes Signed-off-by: Mathieu DEHARBE --- .../server/controller/StudyController.java | 8 +---- .../service/NetworkModificationService.java | 13 +++----- .../server/service/RebuildNodeService.java | 33 +++++++++++++++++-- .../study/server/service/StudyService.java | 17 +--------- 4 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index a71cfa6a7..46b620d56 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -702,13 +702,7 @@ public ResponseEntity mergeModificationsIntoNewComposite( studyService.assertIsStudyAndNodeExist(studyUuid, nodeUuid); studyService.assertCanUpdateNodeInStudy(studyUuid, nodeUuid); studyService.assertNoBlockedNodeInStudy(studyUuid, nodeUuid); - studyService.invalidateNodeTreeWithLF(studyUuid, nodeUuid); - UUID newCompositeUuid; - try { - newCompositeUuid = studyService.mergeModificationsIntoComposite(studyUuid, nodeUuid, modificationsUuids, userId); - } finally { - studyService.unblockNodeTree(studyUuid, nodeUuid); - } + UUID newCompositeUuid = rebuildNodeService.mergeModificationsIntoComposite(studyUuid, nodeUuid, modificationsUuids, userId); return ResponseEntity.ok().body(newCompositeUuid); } diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java index fbef5ade5..6efdca054 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java @@ -301,21 +301,18 @@ public NetworkModificationsResult insertCompositeModifications(UUID groupUuid, } public UUID mergeModificationsIntoComposite( - UUID groupUuid, - List modificationsUuids, - List modificationContexts) { - // TODO : comment différencier de l'autre endpoint ?? - var path = UriComponentsBuilder.fromPath(COMPOSITE_PATH + GROUP_PATH + DELIMITER + "composite-modification"); + List modificationsUuids) { + var path = UriComponentsBuilder.fromPath(COMPOSITE_PATH + DELIMITER + "composite-modification"); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity, List>> httpEntity = new HttpEntity<>( - Pair.of(modificationsUuids, modificationContexts), + HttpEntity> httpEntity = new HttpEntity<>( + modificationsUuids, headers ); return restTemplate.exchange( - getNetworkModificationServerURI(false) + path.buildAndExpand(groupUuid).toUriString(), + getNetworkModificationServerURI(false) + path.toUriString(), HttpMethod.POST, httpEntity, UUID.class diff --git a/src/main/java/org/gridsuite/study/server/service/RebuildNodeService.java b/src/main/java/org/gridsuite/study/server/service/RebuildNodeService.java index 66f141fa1..b95a19e09 100644 --- a/src/main/java/org/gridsuite/study/server/service/RebuildNodeService.java +++ b/src/main/java/org/gridsuite/study/server/service/RebuildNodeService.java @@ -15,6 +15,7 @@ import java.util.Set; import java.util.UUID; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Collectors; @Service @@ -100,6 +101,20 @@ public void moveSubModification( modificationUuid, beforeUuid, userId)); } + public UUID mergeModificationsIntoComposite(UUID studyUuid, UUID nodeUuid, List modificationsUuids, String userId) { + return handleRebuildNodeSupply(studyUuid, nodeUuid, userId, + () -> { + studyService.invalidateNodeTreeWhenMoveModification(studyUuid, nodeUuid); + UUID compositeUuid = null; + try { + compositeUuid = studyService.mergeModificationsIntoComposite(studyUuid, nodeUuid, modificationsUuids, userId); + } finally { + studyService.unblockNodeTree(studyUuid, nodeUuid); + } + return compositeUuid; + }); + } + private void handleMoveNetworkSubmodification(@NonNull UUID studyUuid, @NonNull UUID nodeUuid, UUID sourceCompositeUuid, @@ -133,14 +148,24 @@ private void handleRebuildNode(UUID studyUuid, UUID nodeUuid, String userId, Run handleRebuildNode(studyUuid, nodeUuid, nodeUuid, userId, action); } + private T handleRebuildNodeSupply(UUID studyUuid, UUID nodeUuid, String userId, Supplier action) { + return handleRebuildNodeSupply(studyUuid, nodeUuid, nodeUuid, userId, action); + } + private void handleRebuildNode(UUID studyUuid, UUID node1Uuid, UUID node2Uuid, String userId, Runnable action) { + handleRebuildNodeSupply(studyUuid, node1Uuid, node2Uuid, userId, () -> { + action.run(); + return null; + }); + } + + private T handleRebuildNodeSupply(UUID studyUuid, UUID node1Uuid, UUID node2Uuid, String userId, Supplier action) { // if node 1 and 2 are in the same "subtree", rebuild only the highest one - otherwise, rebuild both List nodesToReBuild = networkModificationTreeService.getHighestNodeUuids(node1Uuid, node2Uuid).stream() .filter(Predicate.not(networkModificationTreeService::isRootOrConstructionNode)).toList(); if (nodesToReBuild.isEmpty()) { - action.run(); - return; + return action.get(); } Map> rootNetworkUuidsByNodeBuilt = nodesToReBuild.stream().collect(Collectors.toMap( @@ -148,7 +173,7 @@ private void handleRebuildNode(UUID studyUuid, UUID node1Uuid, UUID node2Uuid, S nodeUuid -> getRootNetworkWhereNodeIsBuilt(studyUuid, nodeUuid) )); - action.run(); + T result = action.get(); rootNetworkUuidsByNodeBuilt.forEach((nodeUuid, rootNetworkUuids) -> rootNetworkUuids.stream().forEach(rootNetworkUuid -> @@ -160,6 +185,8 @@ private void handleRebuildNode(UUID studyUuid, UUID node1Uuid, UUID node2Uuid, S ) ) ); + + return result; } private Set getRootNetworkWhereNodeIsBuilt(UUID studyUuid, UUID nodeUuid) { diff --git a/src/main/java/org/gridsuite/study/server/service/StudyService.java b/src/main/java/org/gridsuite/study/server/service/StudyService.java index d2e429254..22bf13156 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -2457,22 +2457,7 @@ public UUID mergeModificationsIntoComposite( notificationService.emitStartModificationEquipmentNotification(targetStudyUuid, targetNodeUuid, childrenUuids, NotificationService.MODIFICATIONS_UPDATING_IN_PROGRESS); try { checkStudyContainsNode(targetStudyUuid, targetNodeUuid); - - List studyRootNetworkEntities = getStudyRootNetworks(targetStudyUuid); - UUID groupUuid = networkModificationTreeService.getModificationGroupUuid(targetNodeUuid); - - List modificationApplicationContexts = studyRootNetworkEntities.stream() - .map(rootNetworkEntity -> rootNetworkNodeInfoService.getNetworkModificationApplicationContext(rootNetworkEntity.getId(), targetNodeUuid, rootNetworkEntity.getNetworkUuid())) - .toList(); - - newCompositeUuid = networkModificationService.mergeModificationsIntoComposite( - groupUuid, - modificationsUuids, - modificationApplicationContexts - ); - - // TODO : envoyer une notification pour tout le noeud ?? Mais il est déjà déréalisé - // sendImpactNotifications(targetStudyUuid, targetNodeUuid, networkModificationResults, studyRootNetworkEntities); + newCompositeUuid = networkModificationService.mergeModificationsIntoComposite(modificationsUuids); } finally { notificationService.emitEndModificationEquipmentNotification(targetStudyUuid, targetNodeUuid, childrenUuids); } From 086eb96c28d52d32d22d9d597a47155a9c944f43 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Mon, 18 May 2026 16:05:53 +0200 Subject: [PATCH 5/7] testMergeModificationsIntoNewComposite Signed-off-by: Mathieu DEHARBE --- .../server/service/RebuildNodeService.java | 9 ++-- .../study/server/NetworkModificationTest.java | 47 +++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/service/RebuildNodeService.java b/src/main/java/org/gridsuite/study/server/service/RebuildNodeService.java index b95a19e09..f61c53b43 100644 --- a/src/main/java/org/gridsuite/study/server/service/RebuildNodeService.java +++ b/src/main/java/org/gridsuite/study/server/service/RebuildNodeService.java @@ -102,17 +102,20 @@ public void moveSubModification( } public UUID mergeModificationsIntoComposite(UUID studyUuid, UUID nodeUuid, List modificationsUuids, String userId) { - return handleRebuildNodeSupply(studyUuid, nodeUuid, userId, + return handleRebuildNodeSupply( + studyUuid, + nodeUuid, + userId, () -> { studyService.invalidateNodeTreeWhenMoveModification(studyUuid, nodeUuid); - UUID compositeUuid = null; + UUID compositeUuid; try { compositeUuid = studyService.mergeModificationsIntoComposite(studyUuid, nodeUuid, modificationsUuids, userId); } finally { studyService.unblockNodeTree(studyUuid, nodeUuid); } return compositeUuid; - }); + }); } private void handleMoveNetworkSubmodification(@NonNull UUID studyUuid, diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java index e1c911055..24d818e8f 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java @@ -2116,6 +2116,53 @@ void testInsertComposite() throws Exception { expectedBody); } + @Test + void testMergeModificationsIntoNewComposite() throws Exception { + String userId = "userId"; + StudyEntity studyEntity = insertDummyStudy(UUID.fromString(NETWORK_UUID_STRING), CASE_UUID, "UCTE"); + UUID studyUuid = studyEntity.getId(); + UUID rootNodeUuid = getRootNode(studyUuid).getId(); + + NetworkModificationNode node1 = createNetworkModificationNode(studyUuid, rootNodeUuid, + UUID.randomUUID(), VARIANT_ID, "New node 1", userId); + UUID nodeUuid1 = node1.getId(); + + UUID modification1 = UUID.randomUUID(); + UUID modification2 = UUID.randomUUID(); + List modificationUuids = List.of(modification1, modification2); + String modificationsData = mapper.writeValueAsString(modificationUuids); + + UUID newCompositeUuid = UUID.randomUUID(); + + wireMockServer.stubFor(WireMock.post(WireMock.urlPathMatching("/v1/network-composite-modifications/composite-modification")) + .willReturn(WireMock.ok() + .withBody(mapper.writeValueAsString(newCompositeUuid)) + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))); + + MvcResult mvcResult = mockMvc.perform(post("/v1/studies/{studyUuid}/nodes/{nodeUuid}/composite-modification", + studyUuid, nodeUuid1) + .contentType(MediaType.APPLICATION_JSON) + .content(modificationsData) + .header(USER_ID_HEADER, userId)) + .andExpect(status().isOk()) + .andReturn(); + + UUID resultUuid = mapper.readValue(mvcResult.getResponse().getContentAsString(), UUID.class); + assertEquals(newCompositeUuid, resultUuid); + + checkUpdateStatusMessagesReceived(studyUuid, nodeUuid1, output); + checkEquipmentUpdatingMessagesReceived(studyUuid, nodeUuid1); + checkEquipmentUpdatingFinishedMessagesReceived(studyUuid, nodeUuid1); + checkElementUpdatedMessageSent(studyUuid, userId); + + WireMockUtilsCriteria.verifyPostRequest( + wireMockServer, + "/v1/network-composite-modifications/composite-modification", + Map.of(), + 1 + ); + } + @Test void testDuplicateModification() throws Exception { String userId = "userId"; From 526a44a37231de6058c8347032007d3aba359ec3 Mon Sep 17 00:00:00 2001 From: Mathieu Deharbe <148252167+mathieu-deharbe@users.noreply.github.com> Date: Mon, 18 May 2026 16:14:39 +0200 Subject: [PATCH 6/7] double delimiter Signed-off-by: Mathieu DEHARBE --- .../study/server/service/NetworkModificationService.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java index 6efdca054..b7e610cad 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java @@ -300,9 +300,8 @@ public NetworkModificationsResult insertCompositeModifications(UUID groupUuid, ).getBody(); } - public UUID mergeModificationsIntoComposite( - List modificationsUuids) { - var path = UriComponentsBuilder.fromPath(COMPOSITE_PATH + DELIMITER + "composite-modification"); + public UUID mergeModificationsIntoComposite(@NonNull List modificationsUuids) { + var path = UriComponentsBuilder.fromPath(COMPOSITE_PATH + "composite-modification"); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); From be9e3fb15c1a1d2f411472a4af77ea5621d60664 Mon Sep 17 00:00:00 2001 From: Mathieu DEHARBE Date: Tue, 19 May 2026 18:35:20 +0200 Subject: [PATCH 7/7] simplify endpoint Signed-off-by: Mathieu DEHARBE --- .../study/server/service/NetworkModificationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java index b7e610cad..8bea7f153 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationService.java @@ -301,7 +301,7 @@ public NetworkModificationsResult insertCompositeModifications(UUID groupUuid, } public UUID mergeModificationsIntoComposite(@NonNull List modificationsUuids) { - var path = UriComponentsBuilder.fromPath(COMPOSITE_PATH + "composite-modification"); + var path = UriComponentsBuilder.fromPath(COMPOSITE_PATH); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON);