Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b04a6a2
transmit CompositesToBeInserted
Mathieu-Deharbe Jun 4, 2026
a861027
addReferencesToNewSharedComposites in directory service
Mathieu-Deharbe Jun 12, 2026
0aca8b6
Merge branch 'main' into transmit-composites-to-be-inserted
Mathieu-Deharbe Jun 12, 2026
00bb4ae
stash / unstash
Mathieu-Deharbe Jun 12, 2026
c9e2107
Merge branch 'main' into transmit-composites-to-be-inserted
Mathieu-Deharbe Jun 16, 2026
e97e24d
getReferencesData
Mathieu-Deharbe Jun 16, 2026
1bcd7a4
Merge branch 'main' into transmit-composites-to-be-inserted
Mathieu-Deharbe Jun 17, 2026
09e9813
remove references when deleting studies and nodes
Mathieu-Deharbe Jun 17, 2026
e434747
corrects a few TU including deleteModificationRequest
Mathieu-Deharbe Jun 18, 2026
896d551
corrects a few TU fromNetworkModificationTreeTest
Mathieu-Deharbe Jun 18, 2026
25d10db
corrects TU testDeleteStudyWithNonExistingCase
Mathieu-Deharbe Jun 18, 2026
933f6f6
corrects last TU
Mathieu-Deharbe Jun 18, 2026
fe574d9
adds userId everywhere
Mathieu-Deharbe Jun 18, 2026
3cc7454
testInsertComposite
Mathieu-Deharbe Jun 18, 2026
0bb437b
stash / unstash nodes 6> update references
Mathieu-Deharbe Jun 19, 2026
08c98bb
more specific stubs before
Mathieu-Deharbe Jun 19, 2026
dfdf006
TU on removeReference
Mathieu-Deharbe Jun 19, 2026
a955fe4
SONAR
Mathieu-Deharbe Jun 19, 2026
d6c4c83
comments and renaming
Mathieu-Deharbe Jun 22, 2026
8fc71cf
Merge branch 'main' into transmit-composites-to-be-inserted
Mathieu-Deharbe Jul 7, 2026
2369e75
new sonar locks
Mathieu-Deharbe Jul 7, 2026
5855806
remove references recreation after restoration
Mathieu-Deharbe Jul 7, 2026
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 @@ -24,6 +24,7 @@
import org.gridsuite.study.server.dto.computation.LoadFlowComputationInfos;
import org.gridsuite.study.server.dto.dynamicsimulation.event.EventInfos;
import org.gridsuite.study.server.dto.elasticsearch.EquipmentInfos;
import org.gridsuite.study.server.dto.modification.CompositesToBeInserted;
import org.gridsuite.study.server.dto.modification.ModificationType;
import org.gridsuite.study.server.dto.modification.ModificationsSearchResultByNode;
import org.gridsuite.study.server.dto.modification.NetworkModificationMetadata;
Expand Down Expand Up @@ -178,8 +179,9 @@ public ResponseEntity<CreatedStudyBasicInfos> getStudy(@PathVariable("studyUuid"
@DeleteMapping(value = "/studies/{studyUuid}")
@Operation(summary = "delete the study")
@ApiResponse(responseCode = "200", description = "Study deleted")
public ResponseEntity<Void> deleteStudy(@PathVariable("studyUuid") UUID studyUuid) {
studyService.deleteStudyIfNotCreationInProgress(studyUuid);
public ResponseEntity<Void> deleteStudy(@PathVariable("studyUuid") UUID studyUuid,
@RequestHeader(HEADER_USER_ID) String userId) {
studyService.deleteStudyIfNotCreationInProgress(studyUuid, userId);
return ResponseEntity.ok().build();
}

Expand Down Expand Up @@ -727,29 +729,30 @@ public ResponseEntity<UUID> assembleModificationsIntoNewComposite(
return ResponseEntity.ok().body(newCompositeUuid);
}

/**
* @param modificationsToInsert pair of the composite uuid and its name
*/
@PutMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/composite-modifications", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "For a list of composite network modifications passed in body, insert them into the target node")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The composite modification list has been inserted.")})
public ResponseEntity<Void> insertCompositeModifications(@PathVariable("studyUuid") UUID studyUuid,
@PathVariable("nodeUuid") UUID nodeUuid,
@RequestParam("action") CompositeModificationsActionType action,
@RequestBody List<Pair<UUID, String>> modificationsToInsert,
@RequestBody List<CompositesToBeInserted> compositesToBeInserted,
@RequestHeader(HEADER_USER_ID) String userId) {
studyService.assertIsStudyAndNodeExist(studyUuid, nodeUuid);
studyService.assertCanUpdateNodeInStudy(studyUuid, nodeUuid);
handleInsertCompositeNetworkModifications(studyUuid, nodeUuid, modificationsToInsert, userId, action);
handleInsertCompositeNetworkModifications(studyUuid, nodeUuid, compositesToBeInserted, userId, action);
return ResponseEntity.ok().build();
}

private void handleInsertCompositeNetworkModifications(UUID targetStudyUuid, UUID targetNodeUuid, List<Pair<UUID, String>> modificationsToCopy, String userId,
private void handleInsertCompositeNetworkModifications(
UUID targetStudyUuid,
UUID targetNodeUuid,
List<CompositesToBeInserted> compositesToBeInserted,
String userId,
CompositeModificationsActionType action) {
studyService.assertNoBlockedNodeInStudy(targetStudyUuid, targetNodeUuid);
studyService.invalidateNodeTreeWithLF(targetStudyUuid, targetNodeUuid);
try {
studyService.insertCompositeNetworkModifications(targetStudyUuid, targetNodeUuid, modificationsToCopy, userId, action);
studyService.insertCompositeNetworkModifications(targetStudyUuid, targetNodeUuid, compositesToBeInserted, userId, action);
} finally {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
studyService.unblockNodeTree(targetStudyUuid, targetNodeUuid);
}
Expand Down Expand Up @@ -1454,7 +1457,7 @@ public ResponseEntity<Void> deleteNetworkModifications(@Parameter(description =
}

@PutMapping(value = "/studies/{studyUuid}/nodes/{nodeUuid}/network-modifications", params = "stashed")
@Operation(summary = "Stash network modifications for a node")
@Operation(summary = "Stash or restore network modifications for a node")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The network modifications were stashed / restored "), @ApiResponse(responseCode = "404",
description = "The study/node is not found")})
public ResponseEntity<Void> stashNetworkModifications(@Parameter(description = "Study UUID") @PathVariable("studyUuid") UUID studyUuid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.data.util.Pair;

import java.util.List;
import java.util.UUID;
Expand All @@ -22,5 +23,6 @@ public class DeleteStudyInfos {

private List<RootNetworkInfos> rootNetworkInfosList;

private List<UUID> modificationGroupUuids;
// group uuids as keys and each their own node as values
private List<Pair<UUID, UUID>> modificationGroupUuidsNodeUuids;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
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.study.server.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

import java.util.UUID;

/**
* @author Mathieu Deharbe <mathieu.deharbe at rte-france.com>
* attributes of the references to the shared composites stored in directory server
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ReferenceAttributes {
public enum ReferenceType {
STUDY_NODE,
NETWORK_MODIFICATION,
DIRECTORY_ELEMENT
}

private UUID referenceId;
private ReferenceType referenceType;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
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.study.server.dto.modification;

import java.util.UUID;

/**
* @author Mathieu Deharbe <mathieu.deharbe at rte-france.com>
*/
public record CompositesToBeInserted(UUID id, String name, boolean isShared) { }

Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ private void handleConsumeCaseImportSucceeded(CaseImportReceiver receiver, UUID
} finally {
// if studyEntity is already existing, we don't delete anything in the end of the process
if (caseImportAction == CaseImportAction.STUDY_CREATION) {
studyService.deleteStudyIfNotCreationInProgress(studyUuid);
studyService.deleteStudyIfNotCreationInProgress(studyUuid, userId);
}
if (caseImportAction == CaseImportAction.ROOT_NETWORK_MODIFICATION) {
UUID rootNodeUuid = networkModificationTreeService.getStudyRootNodeUuid(studyUuid);
Expand Down Expand Up @@ -352,7 +352,7 @@ public Consumer<Message<String>> consumeCaseImportFailed() {
UUID rootNetworkUuid = receiver.getRootNetworkUuid();

if (receiver.getCaseImportAction() == CaseImportAction.STUDY_CREATION) {
studyService.deleteStudyIfNotCreationInProgress(studyUuid);
studyService.deleteStudyIfNotCreationInProgress(studyUuid, userId);
notificationService.emitStudyCreationError(studyUuid, userId, errorMessage);
} else {
if (receiver.getCaseImportAction() == CaseImportAction.ROOT_NETWORK_CREATION) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
package org.gridsuite.study.server.service;

import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import org.gridsuite.study.server.RemoteServicesProperties;
import org.gridsuite.study.server.dto.ElementAttributes;
import org.gridsuite.study.server.dto.ReferenceAttributes;
import org.gridsuite.study.server.dto.networkexport.PermissionType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
Expand All @@ -27,6 +29,7 @@
import java.util.*;

import static org.gridsuite.study.server.StudyConstants.*;
import static org.gridsuite.study.server.dto.ReferenceAttributes.ReferenceType.STUDY_NODE;

/**
* @author David Braquart <david.braquart at rte-france.com>
Expand Down Expand Up @@ -99,13 +102,60 @@ public boolean elementExists(UUID directoryUuid, String elementName, String type
return response.getStatusCode() == HttpStatus.OK;
}

/**
*
* @param elementsUuids all the element uuids of the shared composites that need to be referenced in directory server
* @param userId id of the user who started the insertion
* @param targetNodeUuid where the new references will point
*/
public void addReferencesToSharedComposites(@NonNull List<UUID> elementsUuids, String userId, UUID targetNodeUuid) {
Comment on lines +107 to +111

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Java doc and method name is not clear for me. What is the element UID of a shared composite ? What is an insertion ? The references will point to what ? We add or create a new reference ?

elementsUuids.forEach(elementUuid -> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that the method do several rest call is not intuitive

var path = UriComponentsBuilder.fromPath(
DELIMITER + DIRECTORY_API_VERSION + DELIMITER + "elements/{elementUuid}/references")
.buildAndExpand(elementUuid)
.toUriString();

HttpHeaders headers = new HttpHeaders();
headers.set(HEADER_USER_ID, userId);
headers.setContentType(MediaType.APPLICATION_JSON);

ReferenceAttributes referenceAttributes = new ReferenceAttributes(targetNodeUuid, STUDY_NODE);

HttpEntity<ReferenceAttributes> requestEntity = new HttpEntity<>(referenceAttributes, headers);
restTemplate.exchange(getDirectoryServerServerBaseUri() + path, HttpMethod.POST, requestEntity, ElementAttributes.class);
});
}

/**
* remove references from the shared modification in directory server

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of or from ? What kind of references ?

* @param referenceUuid uuid of the composite or group where the 'Modification reference' is located
* @param userId id of the user who caused the unreferencing
* @param sharedElementUuid uuid of the referenced shared element in the directory-server
*/
public void removeReference(UUID referenceUuid, String userId, UUID sharedElementUuid) {
Objects.requireNonNull(referenceUuid);
Objects.requireNonNull(sharedElementUuid);

var path = UriComponentsBuilder.fromPath(
DELIMITER + DIRECTORY_API_VERSION + DELIMITER + "elements/{elementUuid}/references/{referenceUuid}")
.buildAndExpand(sharedElementUuid, referenceUuid)
.toUriString();

HttpHeaders headers = new HttpHeaders();
headers.set(HEADER_USER_ID, userId);
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<Object> requestEntity = new HttpEntity<>(headers);
restTemplate.exchange(getDirectoryServerServerBaseUri() + path, HttpMethod.DELETE, requestEntity, ElementAttributes.class);
}
Comment thread
Mathieu-Deharbe marked this conversation as resolved.

public void createElement(UUID directoryUuid, String description, UUID elementUuid, String elementName, String type, String userId) {
UriComponentsBuilder pathBuilder = UriComponentsBuilder.fromPath(DELIMITER + DIRECTORY_API_VERSION + "/directories/{directoryUuid}/elements");
ElementAttributes elementAttributes = new ElementAttributes(elementUuid, elementName, type, userId, 0, description);
String path = pathBuilder.buildAndExpand(directoryUuid).toUriString();

HttpHeaders headers = new HttpHeaders();
headers.set("userId", userId);
headers.set(HEADER_USER_ID, userId);
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<ElementAttributes> requestEntity = new HttpEntity<>(elementAttributes, headers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.gridsuite.study.server.StudyConstants;
import org.gridsuite.study.server.dto.BuildInfos;
import org.gridsuite.study.server.dto.NodeReceiver;
import org.gridsuite.study.server.dto.modification.CompositesToBeInserted;
import org.gridsuite.study.server.dto.modification.ModificationApplicationContext;
import org.gridsuite.study.server.dto.modification.NetworkModificationMetadata;
import org.gridsuite.study.server.dto.modification.NetworkModificationsResult;
Expand Down Expand Up @@ -68,7 +69,7 @@ public class NetworkModificationService {
}

public void setNetworkModificationServerBaseUri(String networkModificationServerBaseUri) {
this.networkModificationServerBaseUri = networkModificationServerBaseUri + DELIMITER;
this.networkModificationServerBaseUri = networkModificationServerBaseUri;
}

private String getNetworkModificationServerURI(boolean addNetworksPart) {
Expand Down Expand Up @@ -223,6 +224,54 @@ public void restoreModifications(UUID groupUUid, List<UUID> modificationsUuids)
restTemplate.exchange(path, HttpMethod.PUT, httpEntity, Void.class);
}

/**
* @return references data of the modificationsUuids as Pair of :
* - element uuid in directory server
* - uuid of its mother composite (null if the modification is at the root level)
*/
public Map<UUID, UUID> getReferencesData(List<UUID> modificationsUuids) {
Objects.requireNonNull(modificationsUuids);
var path = UriComponentsBuilder
.fromUriString(getNetworkModificationServerURI(false) + "references")
.queryParam(UUIDS, modificationsUuids)
.buildAndExpand()
.toUriString();

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<Map<UUID, UUID>> httpEntity = new HttpEntity<>(headers);

return restTemplate.exchange(
path,
HttpMethod.GET,
httpEntity,
new ParameterizedTypeReference<Map<UUID, UUID>>() { }
).getBody();
}

/**
* @return references data of the modifications in the group as Pairof :
* - element uuid in directory server
* - uuid of its mother composite (null if the modification is at the root level)
*/
public Map<UUID, UUID> getReferencesDataFromGroup(UUID groupUuid) {
Objects.requireNonNull(groupUuid);
var path = UriComponentsBuilder.fromPath(GROUP_PATH + DELIMITER + "references");

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<Map<UUID, UUID>> httpEntity = new HttpEntity<>(headers);

return restTemplate.exchange(
getNetworkModificationServerURI(false) + path.buildAndExpand(groupUuid).toUriString(),
HttpMethod.GET,
httpEntity,
new ParameterizedTypeReference<Map<UUID, UUID>>() { }
).getBody();
}

public void buildNode(@NonNull UUID nodeUuid, @NonNull UUID rootNetworkUuid, @NonNull BuildInfos buildInfos, AbstractWorkflowInfos workflowInfos) {
UUID networkUuid = rootNetworkService.getNetworkUuid(rootNetworkUuid);
String receiver = buildReceiver(nodeUuid, rootNetworkUuid);
Expand Down Expand Up @@ -285,13 +334,13 @@ public NetworkModificationsResult duplicateModifications(UUID groupUuid,

public NetworkModificationsResult insertCompositeModifications(UUID groupUuid,
CompositeModificationsActionType action,
Pair<List<Pair<UUID, String>>, List<ModificationApplicationContext>> modificationContextInfos) {
Pair<List<CompositesToBeInserted>, List<ModificationApplicationContext>> modificationContextInfos) {
var path = UriComponentsBuilder.fromPath(COMPOSITE_PATH + GROUP_PATH)
.queryParam(QUERY_PARAM_ACTION, action.name());

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Pair<List<Pair<UUID, String>>, List<ModificationApplicationContext>>> httpEntity = new HttpEntity<>(modificationContextInfos, headers);
HttpEntity<Pair<List<CompositesToBeInserted>, List<ModificationApplicationContext>>> httpEntity = new HttpEntity<>(modificationContextInfos, headers);

return restTemplate.exchange(
getNetworkModificationServerURI(false) + path.buildAndExpand(groupUuid).toUriString(),
Expand Down
Loading