Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
583597e
rework export network file
ghazwarhili Dec 12, 2025
5271580
Merge branch 'main' into rework-export-network-file
ghazwarhili Dec 12, 2025
3c26cdc
add changeset
ghazwarhili Dec 12, 2025
d475144
Merge remote-tracking branch 'origin/rework-export-network-file' into…
ghazwarhili Dec 12, 2025
3391759
revert unused import
ghazwarhili Dec 12, 2025
ddcaa17
fix TU
ghazwarhili Dec 15, 2025
1b3ee60
fix TU
ghazwarhili Dec 15, 2025
06d1a60
enhance coverage code
ghazwarhili Dec 16, 2025
7b84c83
enhance coverage test
ghazwarhili Dec 16, 2025
5aa25e2
unused import
ghazwarhili Dec 16, 2025
0cdebf0
Merge branch 'main' into rework-export-network-file
ghazwarhili Dec 16, 2025
1bdb4cf
code review remarks
ghazwarhili Dec 16, 2025
0a6c2d1
Merge remote-tracking branch 'origin/rework-export-network-file' into…
ghazwarhili Dec 16, 2025
54e641a
code review remarks
ghazwarhili Dec 17, 2025
5cc81d5
revert formatted code
ghazwarhili Dec 17, 2025
e0df4cf
resolve conflicts
ghazwarhili Dec 17, 2025
169806e
remove nodeUuid and rootNetworkUuid from notification
ghazwarhili Dec 17, 2025
993b15d
replace map by list
ghazwarhili Dec 17, 2025
0ef74aa
fix TU
ghazwarhili Dec 17, 2025
ef4e3d7
add clearNodeExportNetworks
ghazwarhili Dec 17, 2025
06cd2ee
Merge branch 'main' into rework-export-network-file
ghazwarhili Dec 17, 2025
5bb4086
add unique key contraint for export uuid
ghazwarhili Dec 17, 2025
a1f61cb
Merge remote-tracking branch 'origin/rework-export-network-file' into…
ghazwarhili Dec 17, 2025
e1e1e8a
fix TU
ghazwarhili Dec 17, 2025
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 @@ -14,6 +14,7 @@
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 jakarta.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import org.gridsuite.filter.globalfilter.GlobalFilter;
import org.gridsuite.filter.utils.EquipmentType;
Expand All @@ -34,6 +35,7 @@
import org.gridsuite.study.server.dto.elasticsearch.EquipmentInfos;
import org.gridsuite.study.server.dto.modification.ModificationType;
import org.gridsuite.study.server.dto.modification.ModificationsSearchResultByNode;
import org.gridsuite.study.server.dto.networkexport.ExportNetworkStatus;
import org.gridsuite.study.server.dto.sensianalysis.SensitivityAnalysisCsvFileInfos;
import org.gridsuite.study.server.dto.sensianalysis.SensitivityFactorsIdsByGroup;
import org.gridsuite.study.server.dto.sequence.NodeSequenceType;
Expand All @@ -48,6 +50,7 @@
import org.gridsuite.study.server.service.shortcircuit.FaultResultsMode;
import org.gridsuite.study.server.service.shortcircuit.ShortcircuitAnalysisType;
import org.gridsuite.study.server.utils.ResultParameters;
import org.springframework.core.io.Resource;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.util.Pair;
Expand All @@ -61,7 +64,6 @@
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import jakarta.annotation.Nullable;
import java.beans.PropertyEditorSupport;
import java.util.*;

Expand Down Expand Up @@ -997,6 +999,26 @@ public ResponseEntity<UUID> exportNetwork(
return ResponseEntity.ok().body(exportUuid);
}

@GetMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/download-file")
@Operation(summary = "Download exported network file")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "The file is downloaded"),
@ApiResponse(responseCode = "409", description = "Export not ready yet")
})
public ResponseEntity<Resource> downloadExportedNetworkFile(
@Parameter(description = "Study UUID") @PathVariable("studyUuid") UUID studyUuid,
@Parameter(description = "Root Network UUID") @PathVariable("rootNetworkUuid") UUID rootNetworkUuid,
@Parameter(description = "Node UUID") @PathVariable("nodeUuid") UUID nodeUuid,
@Parameter(description = "Export UUID") @RequestParam("exportUuid") UUID exportUuid,
@RequestHeader(HEADER_USER_ID) String userId) {
studyService.assertRootNodeOrBuiltNode(studyUuid, nodeUuid, rootNetworkUuid);
ExportNetworkStatus status = rootNetworkNodeInfoService.getExportNetworkStatus(nodeUuid, rootNetworkUuid, exportUuid);
if (status == ExportNetworkStatus.RUNNING) {
return ResponseEntity.status(HttpStatus.CONFLICT).contentType(MediaType.APPLICATION_JSON).body(null);
}
return networkConversionService.downloadExportedNetworkFile(exportUuid, userId);
}

@PostMapping(value = "/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/security-analysis/run")
@Operation(summary = "run security analysis on study")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "The security analysis has started")})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
import lombok.Getter;
import lombok.Setter;
import org.gridsuite.study.server.networkmodificationtree.dto.NodeBuildStatus;
import org.gridsuite.study.server.networkmodificationtree.entities.NodeExportEmbeddable;
import org.gridsuite.study.server.networkmodificationtree.entities.RootNetworkNodeInfoEntity;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

Expand Down Expand Up @@ -54,6 +57,8 @@ public class RootNetworkNodeInfo {

private NodeBuildStatus nodeBuildStatus;

private List<NodeExportEmbeddable> nodeExportNetwork;

public RootNetworkNodeInfoEntity toEntity() {
return RootNetworkNodeInfoEntity.builder()
.id(id)
Expand All @@ -72,6 +77,7 @@ public RootNetworkNodeInfoEntity toEntity() {
.stateEstimationResultUuid(stateEstimationResultUuid)
.pccMinResultUuid(pccMinResultUuid)
.nodeBuildStatus(nodeBuildStatus.toEntity())
.nodeExportNetwork(nodeExportNetwork != null ? nodeExportNetwork : new ArrayList<>())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.gridsuite.study.server.dto.networkexport;

public enum ExportNetworkStatus {
RUNNING,
SUCCESS,
FAILED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2025, 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.networkmodificationtree.entities;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import lombok.*;
import org.gridsuite.study.server.dto.networkexport.ExportNetworkStatus;

import java.util.UUID;

/**
* @author Rehili Ghazwa <ghazwa.rehili at rte-france.com>
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Embeddable
public class NodeExportEmbeddable {

@Column(name = "export_uuid", nullable = false, unique = true)
private UUID exportUuid;

@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false)
private ExportNetworkStatus status;

public static NodeExportEmbeddable toNodeExportEmbeddable(UUID exportUuid, ExportNetworkStatus status) {
return NodeExportEmbeddable.builder()
.exportUuid(exportUuid)
.status(status)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
import org.gridsuite.study.server.dto.RootNetworkNodeInfo;
import org.gridsuite.study.server.repository.rootnetwork.RootNetworkEntity;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.*;

/**
* @author Le Saulnier Kevin <lesaulnier.kevin at rte-france.com>
Expand Down Expand Up @@ -102,6 +99,14 @@ public class RootNetworkNodeInfoEntity {
@Column(name = "pccMinResultUuid")
private UUID pccMinResultUuid;

@ElementCollection
@CollectionTable(
name = "node_export",
joinColumns = @JoinColumn(name = "root_network_node_info_id"),
foreignKey = @ForeignKey(name = "rootNetworkNodeInfo_nodeExport_fk")
)
private List<NodeExportEmbeddable> nodeExportNetwork = new ArrayList<>();

@Column(name = "blockedNode")
private Boolean blockedNode;

Expand Down Expand Up @@ -137,6 +142,7 @@ public RootNetworkNodeInfo toDto() {
.voltageInitResultUuid(voltageInitResultUuid)
.shortCircuitAnalysisResultUuid(shortCircuitAnalysisResultUuid)
.variantId(variantId)
.nodeExportNetwork(nodeExportNetwork)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public interface RootNetworkNodeInfoRepository extends JpaRepository<RootNetwork

List<RootNetworkNodeInfoEntity> findAllByPccMinResultUuidNotNull();

List<RootNetworkNodeInfoEntity> findAllByNodeExportNetworkExportUuid(UUID exportUuid);

List<RootNetworkNodeInfoEntity> findAllByNodeInfoId(UUID nodeInfoId);

@EntityGraph(attributePaths = {"rootNetwork"}, type = EntityGraph.EntityGraphType.LOAD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.gridsuite.study.server.dto.caseimport.CaseImportReceiver;
import org.gridsuite.study.server.dto.dynamicsimulation.DynamicSimulationParametersInfos;
import org.gridsuite.study.server.dto.modification.NetworkModificationResult;
import org.gridsuite.study.server.dto.networkexport.ExportNetworkStatus;
import org.gridsuite.study.server.dto.networkexport.NetworkExportReceiver;
import org.gridsuite.study.server.dto.workflow.RerunLoadFlowInfos;
import org.gridsuite.study.server.dto.workflow.WorkflowType;
Expand Down Expand Up @@ -848,6 +849,7 @@ public void consumeNetworkExportFinished(Message<String> msg) {
UUID exportUuid = msg.getHeaders().containsKey(HEADER_EXPORT_UUID) ? UUID.fromString((String) Objects.requireNonNull(msg.getHeaders().get(HEADER_EXPORT_UUID))) : null;
String errorMessage = (String) msg.getHeaders().get(HEADER_ERROR);
notificationService.emitNetworkExportFinished(studyUuid, exportUuid, userId, errorMessage);
rootNetworkNodeInfoService.updateExportNetworkStatus(exportUuid, errorMessage == null ? ExportNetworkStatus.SUCCESS : ExportNetworkStatus.FAILED);
} catch (Exception e) {
LOGGER.error(e.toString(), e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
import org.gridsuite.study.server.dto.RootNetworkInfos;
import org.gridsuite.study.server.dto.caseimport.CaseImportAction;
import org.gridsuite.study.server.dto.caseimport.CaseImportReceiver;
import org.gridsuite.study.server.error.StudyException;
import org.gridsuite.study.server.dto.networkexport.NetworkExportReceiver;
import org.gridsuite.study.server.error.StudyException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
Expand All @@ -34,7 +35,7 @@
import java.util.UUID;

import static org.gridsuite.study.server.StudyConstants.*;
import static org.gridsuite.study.server.error.StudyBusinessErrorCode.*;
import static org.gridsuite.study.server.error.StudyBusinessErrorCode.NETWORK_EXPORT_FAILED;

@Service
public class NetworkConversionService {
Expand Down Expand Up @@ -129,6 +130,23 @@ public UUID exportNetwork(UUID networkUuid, UUID studyUuid, String variantId, St
}
}

public ResponseEntity<Resource> downloadExportedNetworkFile(UUID exportUuid, String userId) {
String path = UriComponentsBuilder.fromPath(DELIMITER + NETWORK_CONVERSION_API_VERSION + "/download-file/{exportUuid}")
.buildAndExpand(exportUuid)
.toUriString();

HttpHeaders headers = new HttpHeaders();
headers.set(HEADER_USER_ID, userId);
HttpEntity<Void> entity = new HttpEntity<>(headers);

return restTemplate.exchange(
networkConversionServerBaseUri + path,
HttpMethod.GET,
entity,
Resource.class
);
}

public void setNetworkConversionServerBaseUri(String networkConversionServerBaseUri) {
this.networkConversionServerBaseUri = networkConversionServerBaseUri;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,18 @@
import com.powsybl.timeseries.DoubleTimeSeries;
import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.gridsuite.study.server.error.StudyException;
import org.gridsuite.study.server.dto.*;
import org.gridsuite.study.server.dto.computation.LoadFlowComputationInfos;
import org.gridsuite.study.server.dto.dynamicsecurityanalysis.DynamicSecurityAnalysisStatus;
import org.gridsuite.study.server.dto.dynamicsimulation.DynamicSimulationStatus;
import org.gridsuite.study.server.dto.modification.ModificationApplicationContext;
import org.gridsuite.study.server.dto.networkexport.ExportNetworkStatus;
import org.gridsuite.study.server.dto.sensianalysis.SensitivityAnalysisCsvFileInfos;
import org.gridsuite.study.server.dto.timeseries.TimeSeriesMetadataInfos;
import org.gridsuite.study.server.dto.timeseries.TimelineEventInfos;
import org.gridsuite.study.server.error.StudyException;
import org.gridsuite.study.server.networkmodificationtree.dto.BuildStatus;
import org.gridsuite.study.server.networkmodificationtree.entities.NetworkModificationNodeInfoEntity;
import org.gridsuite.study.server.networkmodificationtree.entities.NetworkModificationNodeType;
import org.gridsuite.study.server.networkmodificationtree.entities.NodeBuildStatusEmbeddable;
import org.gridsuite.study.server.networkmodificationtree.entities.RootNetworkNodeInfoEntity;
import org.gridsuite.study.server.networkmodificationtree.entities.*;
import org.gridsuite.study.server.repository.StudyEntity;
import org.gridsuite.study.server.repository.networkmodificationtree.NetworkModificationNodeInfoRepository;
import org.gridsuite.study.server.repository.rootnetwork.RootNetworkEntity;
Expand All @@ -45,9 +43,10 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.gridsuite.study.server.error.StudyBusinessErrorCode.*;
import static org.gridsuite.study.server.dto.ComputationType.*;
import static org.gridsuite.study.server.dto.InvalidateNodeTreeParameters.ComputationsInvalidationMode;
import static org.gridsuite.study.server.error.StudyBusinessErrorCode.*;
import static org.gridsuite.study.server.networkmodificationtree.entities.NodeExportEmbeddable.toNodeExportEmbeddable;

/**
* @author Slimane amar <slimane.amar at rte-france.com
Expand Down Expand Up @@ -858,4 +857,54 @@ public void stopPccMin(UUID studyUuid, UUID nodeUuid, UUID rootNetworkUuid) {
UUID resultUuid = getComputationResultUuid(nodeUuid, rootNetworkUuid, PCC_MIN);
pccMinService.stopPccMin(studyUuid, nodeUuid, rootNetworkUuid, resultUuid);
}

@Transactional
public void updateExportNetworkStatus(UUID exportUuid, ExportNetworkStatus status) {
RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity = rootNetworkNodeInfoRepository.findAllByNodeExportNetworkExportUuid(exportUuid)
.stream()
.filter(rootNetworkNodeInfo -> rootNetworkNodeInfo.getNodeExportNetwork()
.stream().anyMatch(nodeExportEmbeddable -> nodeExportEmbeddable.getExportUuid().equals(exportUuid)))
.findFirst()
.orElseThrow(() -> new StudyException(NOT_FOUND, "Root network not found for exportUuid=" + exportUuid));
rootNetworkNodeInfoEntity.getNodeExportNetwork().stream()
.filter(nodeExportEmbeddable -> nodeExportEmbeddable.getExportUuid().equals(exportUuid))
.findFirst()
.ifPresentOrElse(nodeExportEmbeddable -> nodeExportEmbeddable.setStatus(status),
() -> rootNetworkNodeInfoEntity.getNodeExportNetwork().add(toNodeExportEmbeddable(exportUuid, status)));
}

@Transactional
public void updateExportNetworkStatus(UUID nodeUuid, UUID rootNetworkUuid, UUID exportUuid, ExportNetworkStatus status) {
RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity = findRootNetworkNodeInfo(nodeUuid, rootNetworkUuid);
rootNetworkNodeInfoEntity.getNodeExportNetwork().stream()
.filter(e -> e.getExportUuid().equals(exportUuid))
.findFirst()
.ifPresentOrElse(nodeExportEmbeddable -> nodeExportEmbeddable.setStatus(status),
() -> rootNetworkNodeInfoEntity.getNodeExportNetwork().add(toNodeExportEmbeddable(exportUuid, status)));
}

@Transactional
public ExportNetworkStatus getExportNetworkStatus(UUID nodeUuid, UUID rootNetworkUuid, UUID exportUuid) {
RootNetworkNodeInfoEntity rootNetworkNodeInfoEntity = findRootNetworkNodeInfo(nodeUuid, rootNetworkUuid);
return rootNetworkNodeInfoEntity.getNodeExportNetwork().stream()
.filter(nodeExportEmbeddable -> nodeExportEmbeddable.getExportUuid().equals(exportUuid))
.map(NodeExportEmbeddable::getStatus)
.findFirst()
.orElseThrow(() -> new StudyException(NOT_FOUND, "Export network not found for exportUuid=" + exportUuid));
}

private RootNetworkNodeInfoEntity findRootNetworkNodeInfo(UUID nodeUuid, UUID rootNetworkUuid) {
return rootNetworkNodeInfoRepository.findByNodeInfoIdAndRootNetworkId(nodeUuid, rootNetworkUuid)
.orElseThrow(() -> new StudyException(NOT_FOUND, "Root network not found"));
}

@Transactional
public void clearNodeExportNetworks(UUID nodeUuid, UUID rootNetworkUuid) {
RootNetworkNodeInfoEntity rootNetworkNodeInfo = findRootNetworkNodeInfo(nodeUuid, rootNetworkUuid);
if (rootNetworkNodeInfo.getNodeExportNetwork() != null) {
rootNetworkNodeInfo.getNodeExportNetwork().clear();
} else {
rootNetworkNodeInfo.setNodeExportNetwork(new ArrayList<>());
}
}
}
Loading