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 @@ -144,6 +144,19 @@ public ResponseEntity<Map<UUID, UUID>> getParentComposites(
.body(networkModificationService.findModificationParentComposites(networkModificationUuids));
}

/**
* @return modification uuid -> uuid of the top-level group ultimately containing it, walking up through as
* many nested composite modifications as needed; modifications not reachable from any group have no entry
*/
@GetMapping(value = "/root-groups", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "For each given network modification, find the top-level group ultimately containing it")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The root groups were returned")})
public ResponseEntity<Map<UUID, UUID>> getRootGroups(
@Parameter(description = "Network modification UUIDs") @RequestParam("uuids") List<UUID> networkModificationUuids) {
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON)
.body(networkModificationService.findModificationRootGroups(networkModificationUuids));
}

@PutMapping(value = "/{uuid}/replace", consumes = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Replaces all the network modifications inside a network composite modification")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The composite modification has been updated")})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,9 @@ public CompletableFuture<ResponseEntity<NetworkModificationsResult>> createNetwo
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The network modification was updated")})
public ResponseEntity<Void> updateNetworkModification(
@Parameter(description = "Network modification UUID") @PathVariable("uuid") UUID networkModificationUuid,
@RequestBody ModificationInfos modificationInfos) {
networkModificationService.updateNetworkModification(networkModificationUuid, modificationInfos);
@RequestBody ModificationInfos modificationInfos,
@RequestHeader("userId") String userId) {
networkModificationService.updateNetworkModification(networkModificationUuid, modificationInfos, userId);
return ResponseEntity.ok().build();
}

Expand Down Expand Up @@ -313,8 +314,9 @@ public ResponseEntity<List<ReferenceData>> getAllReferencesDataFromGroup(
@ApiResponse(responseCode = "200", description = "The metadata of the network modifications has been successfully updated")
public ResponseEntity<Void> updateNetworkModificationMetadata(
@Parameter(description = "Network modifications UUIDs") @RequestParam("uuids") List<UUID> networkModificationUuids,
@RequestBody ModificationInfos metadata) {
networkModificationService.updateNetworkModificationMetadata(networkModificationUuids, metadata);
@RequestBody ModificationInfos metadata, @RequestHeader("userId") String userId) {

networkModificationService.updateNetworkModificationMetadata(networkModificationUuids, metadata, userId);
return ResponseEntity.ok().build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import org.gridsuite.modification.server.entities.CompositeModificationEntity;
import org.gridsuite.modification.server.entities.ModificationEntity;
import org.gridsuite.modification.server.entities.ModificationReferenceEntity;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.NativeQuery;
Expand Down Expand Up @@ -98,6 +99,31 @@ SELECT CAST(m.id AS VARCHAR), CAST(m.container_id AS VARCHAR)
""", nativeQuery = true)
List<Object[]> findCompositeContainerIdsByModificationIds(@Param("uuids") Collection<UUID> uuids);

/**
* For each given modification, walks up the {@code container_id} chain (a modification may live in a
* COMPOSITE that is itself nested in another container) until it reaches the enclosing GROUP.
* Modifications sitting directly in a group are resolved in one step.
*
* @return one [modification id, root group id] row per given modification uuid that is actually reachable
* from a group; ids not found (deleted, or orphaned from any group) have no row
*/
@Query(value = """
WITH RECURSIVE container_chain(modification_id, current_container_id) AS (
SELECT m.id AS modification_id, m.container_id AS current_container_id
FROM modification m
WHERE m.id IN :uuids
UNION ALL
SELECT cc.modification_id, m2.container_id
FROM container_chain cc
JOIN modification m2 ON m2.id = cc.current_container_id
)
SELECT CAST(cc.modification_id AS VARCHAR), CAST(cc.current_container_id AS VARCHAR)
FROM container_chain cc
JOIN modification_container c ON c.id = cc.current_container_id
WHERE c.type = 'GROUP'
""", nativeQuery = true)
List<Object[]> findRootGroupIdsByModificationIds(@Param("uuids") Collection<UUID> uuids);

@Query("""
SELECT COUNT(m) FROM ModificationEntity m
WHERE m.container.id = :containerId AND m.stashed = :stashed
Expand All @@ -109,6 +135,10 @@ SELECT COUNT(m) FROM ModificationEntity m
"from ModificationEntity m WHERE m.id = (select r.referenceId from ModificationReferenceEntity r WHERE r.id = ?1)")
ModificationEntity findReferencedModificationMetadataByReferenceId(UUID uuid);

// return all the modification-references pointing at a given element (e.g. a composite shared from directory-server)
@Query("SELECT r FROM ModificationReferenceEntity r WHERE r.referenceId = :elementUuid")
List<ModificationReferenceEntity> findAllByReferenceId(@Param("elementUuid") UUID elementUuid);

@Query(value = "SELECT cast(operational_limits_groups_id AS VARCHAR) FROM line_modification_operational_limits_groups WHERE branch_id IN ?1", nativeQuery = true)
List<UUID> findLineModificationOpLimitsGroupsIdsByBranchIds(List<UUID> uuids);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,32 @@ private List<ModificationInfos> getUnstashedModificationsInfosNonTransactional(U
return getModificationEntityStream(groupUuid).filter(m -> !m.getStashed()).map(this::toModificationsInfosOptimized).toList();
}

/**
* @return ancestor composite modification uuids, closest first; empty if the modification is a
* direct child of a group (not nested in any composite)
*/
@Transactional(readOnly = true)
public List<UUID> findAncestorCompositeUuids(@NonNull UUID modificationUuid) {
List<UUID> ancestors = new ArrayList<>();
Set<UUID> visited = new HashSet<>();
UUID currentContainerId = modificationRepository.findById(modificationUuid)
.map(ModificationEntity::getContainerUuid)
.orElse(null);

while (currentContainerId != null && visited.add(currentContainerId)) {
ModificationContainerType containerType = modificationContainerRepository.getTypeById(currentContainerId);
if (containerType != ModificationContainerType.COMPOSITE) {
break; // reached a GROUP (a study node's own modifications) : top of the tree
}
ancestors.add(currentContainerId);
// the composite container shares its id with the CompositeModificationEntity that owns it
currentContainerId = modificationRepository.findById(currentContainerId)
.map(ModificationEntity::getContainerUuid)
.orElse(null);
}
return ancestors;
}

/**
* @return ReferenceData : modification and elementUuid of the shared modification -> Uuid of the composite containing the reference, null if the modification reference is at the root level
*/
Expand All @@ -789,6 +815,18 @@ public List<ReferenceData> getReferences(@NonNull List<UUID> modificationUuids)
return references;
}

/**
* @return one ReferenceData per modification-reference pointing at {@code elementUuid} (e.g. a
* composite shared from directory-server), empty if nothing references it
*/
@Transactional(readOnly = true)
public List<ReferenceData> getReferencesByElementUuid(@NonNull UUID elementUuid) {
return modificationRepository.findAllByReferenceId(elementUuid).stream()
.map(reference -> new ReferenceData(reference.getId(), reference.getReferenceId(),
modificationRepository.findCompositeContainerIdByModificationId(reference.getId())))
.toList();
}

@Transactional
public void stashNetworkModifications(@NonNull List<UUID> modificationUuids, int stashedModificationCount) {
int stashModificationOrder = -stashedModificationCount - 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,13 +275,20 @@
}

@Transactional
public void updateNetworkModification(@NonNull UUID modificationUuid, @NonNull ModificationInfos modificationInfos) {
public void updateNetworkModification(@NonNull UUID modificationUuid, @NonNull ModificationInfos modificationInfos, @NonNull String userId) {
networkModificationRepository.updateModification(modificationUuid, modificationInfos);
// Notify directory-server once per ancestor composite (closest first)
List<UUID> ancestorCompositeUuids = networkModificationRepository.findAncestorCompositeUuids(modificationUuid);
ancestorCompositeUuids.forEach(compositeUuid ->
notificationService.emitElementUpdated(compositeUuid, userId));
}

@Transactional
public void updateNetworkModificationMetadata(@NonNull List<UUID> modificationUuids, @NonNull ModificationInfos metadata) {
public void updateNetworkModificationMetadata(@NonNull List<UUID> modificationUuids, @NonNull ModificationInfos metadata, @NonNull String userId) {
networkModificationRepository.updateNetworkModificationMetadata(modificationUuids, metadata);
//List<UUID> ancestorCompositeUuids = networkModificationRepository.findAncestorCompositeUuids(modificationUuids.getFirst());

Check warning on line 289 in src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This block of commented-out lines of code should be removed.

See more on https://sonarcloud.io/project/issues?id=org.gridsuite%3Anetwork-modification-server&issues=AaBCDkgcpd3zLPn6lNYf&open=AaBCDkgcpd3zLPn6lNYf&pullRequest=877
//ancestorCompositeUuids.forEach(compositeUuid -> notificationService.emitElementUpdated(compositeUuid, userId));

}

@Transactional
Expand All @@ -297,6 +304,14 @@
row -> UUID.fromString((String) row[1])));
}

@Transactional(readOnly = true)
public Map<UUID, UUID> findModificationRootGroups(@NonNull List<UUID> modificationUuids) {
return modificationRepository.findRootGroupIdsByModificationIds(modificationUuids).stream()
.collect(Collectors.toMap(
row -> UUID.fromString((String) row[0]),
row -> UUID.fromString((String) row[1])));
}

@Transactional
public void stashNetworkModifications(UUID groupUuid, @NonNull List<UUID> modificationUuids) {
for (UUID modificationUuid : modificationUuids) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.UUID;

/**
* @author Seddik Yengui <seddik.yengui at rte-france.com>
*/
Expand All @@ -32,6 +35,9 @@ public class NotificationService {
public static final String WORKFLOW_TYPE_HEADER = "workflowType";
public static final String WORKFLOW_INFOS_HEADER = "workflowInfos";
public static final String NETWORK_UUID_HEADER = "networkUuid";
public static final String HEADER_ELEMENT_UUID = "elementUuid";
public static final String HEADER_MODIFIED_BY = "modifiedBy";
public static final String HEADER_MODIFICATION_DATE = "modificationDate";

@Autowired
private StreamBridge publisher;
Expand Down Expand Up @@ -66,4 +72,19 @@ public void emitCancelBuildMessage(@NonNull String receiver) {
.build();
sendMessage(message, "publishCancelBuild-out-0");
}

/**
* Tells directory-server that {@code elementUuid} (typically a composite modification's uuid,
* which is also its directory element uuid) was modified. directory-server is the sole holder
* of the "who references what" graph: it decides on its own whether {@code elementUuid} is a
* shared element and who needs to be notified further.
*/
public void emitElementUpdated(@NonNull UUID elementUuid, @NonNull String userId) {
Message<String> message = MessageBuilder.withPayload("")
.setHeader(HEADER_ELEMENT_UUID, elementUuid)
.setHeader(HEADER_MODIFIED_BY, userId)
.setHeader(HEADER_MODIFICATION_DATE, Instant.now())
.build();
sendMessage(message, "publishElementUpdate-out-0");
}
}
4 changes: 3 additions & 1 deletion src/main/resources/config/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ spring:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}build.cancel
publishStoppedBuild-out-0:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}build.stopped
output-bindings: publishBuild-out-0;publishResultBuild-out-0;publishCancelBuild-out-0;publishStoppedBuild-out-0
publishElementUpdate-out-0:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}element.update
output-bindings: publishBuild-out-0;publishResultBuild-out-0;publishCancelBuild-out-0;publishStoppedBuild-out-0;publishElementUpdate-out-0
rabbit:
bindings:
consumeBuild1-in-0: &consumeBuildRabbitConfig
Expand Down
Loading
Loading