Skip to content

Commit 087db83

Browse files
authored
Merge branch 'main' into addTagProperties
2 parents b3da791 + c0d341f commit 087db83

File tree

8 files changed

+181
-32
lines changed

8 files changed

+181
-32
lines changed

src/main/java/org/gridsuite/modification/server/dto/catalog/LineTypeInfos.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,6 @@ public class LineTypeInfos {
6767

6868
@JsonIgnore
6969
public LineTypeEntity toEntity() {
70-
throw new UnsupportedOperationException("TODO");
70+
throw new UnsupportedOperationException("toEntity() should be implemented in subclasses");
7171
}
7272
}

src/main/java/org/gridsuite/modification/server/modifications/NetworkModificationApplicator.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,18 @@ public NetworkModificationResult applyModifications(ModificationApplicationGroup
106106
.orElse(PreloadingStrategy.NONE);
107107

108108
NetworkStoreListener listener = NetworkStoreListener.create(networkInfos.getNetwork(), networkInfos.getNetworkUuuid(), networkStoreService, equipmentInfosService, applicationInfosService, collectionThreshold);
109-
ApplicationStatus groupApplicationStatus;
110109
if (preloadingStrategy == PreloadingStrategy.ALL_COLLECTIONS_NEEDED_FOR_BUS_VIEW) {
111-
groupApplicationStatus = largeNetworkModificationExecutionService
112-
.supplyAsync(() -> apply(modificationInfosGroup, listener))
110+
return largeNetworkModificationExecutionService
111+
.supplyAsync(() -> applyAndFlush(modificationInfosGroup, listener))
113112
.join();
114113
} else {
115-
groupApplicationStatus = apply(modificationInfosGroup, listener);
114+
return applyAndFlush(modificationInfosGroup, listener);
116115
}
116+
}
117117

118-
return flushModificationApplications(groupApplicationStatus, listener);
118+
private NetworkModificationResult applyAndFlush(ModificationApplicationGroup modificationInfosGroup,
119+
NetworkStoreListener listener) {
120+
return flushModificationApplications(apply(modificationInfosGroup, listener), listener);
119121
}
120122

121123
private NetworkModificationResult flushModificationApplications(ApplicationStatus groupApplicationStatus, NetworkStoreListener listener) {
@@ -147,16 +149,18 @@ public NetworkModificationResult applyModifications(List<ModificationApplication
147149
.orElse(PreloadingStrategy.NONE);
148150

149151
NetworkStoreListener listener = NetworkStoreListener.create(networkInfos.getNetwork(), networkInfos.getNetworkUuuid(), networkStoreService, equipmentInfosService, applicationInfosService, collectionThreshold);
150-
List<ApplicationStatus> groupsApplicationStatuses;
151152
if (preloadingStrategy == PreloadingStrategy.ALL_COLLECTIONS_NEEDED_FOR_BUS_VIEW) {
152-
groupsApplicationStatuses = largeNetworkModificationExecutionService
153-
.supplyAsync(() -> apply(modificationInfosGroups, listener))
153+
return largeNetworkModificationExecutionService
154+
.supplyAsync(() -> applyAndFlush(modificationInfosGroups, listener))
154155
.join();
155156
} else {
156-
groupsApplicationStatuses = apply(modificationInfosGroups, listener);
157+
return applyAndFlush(modificationInfosGroups, listener);
157158
}
159+
}
158160

159-
return flushModificationApplications(groupsApplicationStatuses, listener);
161+
private NetworkModificationResult applyAndFlush(List<ModificationApplicationGroup> modificationInfosGroups,
162+
NetworkStoreListener listener) {
163+
return flushModificationApplications(apply(modificationInfosGroups, listener), listener);
160164
}
161165

162166
// This method is used when building a variant

src/main/java/org/gridsuite/modification/server/repositories/NetworkModificationRepository.java

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,20 @@ public void deleteAll() {
106106
}
107107

108108
@Transactional // To have all create in the same transaction (atomic)
109-
// TODO Remove transaction when errors will no longer be sent to the front
110109
// This method should be package-private and not used as API of the service as it uses ModificationEntity and
111110
// we want to encapsulate the use of Entity related objects to this service.
112111
// Nevertheless We have to keep it public for transactional annotation.
113112
public List<ModificationEntity> saveModifications(UUID groupUuid, List<ModificationEntity> modifications) {
114113
return saveModificationsNonTransactional(groupUuid, modifications);
115114
}
116115

117-
@Transactional // To have all create in the same transaction (atomic)
118-
// TODO Remove transaction when errors will no longer be sent to the front
116+
@Transactional
119117
public List<ModificationEntity> saveModificationInfos(UUID groupUuid, List<ModificationInfos> modifications) {
118+
return saveModificationInfosNonTransactional(groupUuid, modifications);
119+
}
120+
121+
private List<ModificationEntity> saveModificationInfosNonTransactional(UUID groupUuid,
122+
List<ModificationInfos> modifications) {
120123
List<ModificationEntity> entities = modifications.stream().map(ModificationEntity::fromDTO).toList();
121124

122125
return saveModificationsNonTransactional(groupUuid, entities);
@@ -165,8 +168,13 @@ private List<ModificationEntity> saveModificationsNonTransactional(UUID groupUui
165168
}
166169

167170
@Transactional
168-
// TODO Remove transaction when errors will no longer be sent to the front
169171
public List<ModificationEntity> moveModifications(UUID destinationGroupUuid, UUID originGroupUuid, List<UUID> modificationsToMoveUUID, UUID referenceModificationUuid) {
172+
List<ModificationEntity> movedModifications = moveModificationsNonTransactional(destinationGroupUuid, originGroupUuid, modificationsToMoveUUID, referenceModificationUuid);
173+
loadFullModificationsEntities(movedModifications);
174+
return movedModifications;
175+
}
176+
177+
private List<ModificationEntity> moveModificationsNonTransactional(UUID destinationGroupUuid, UUID originGroupUuid, List<UUID> modificationsToMoveUUID, UUID referenceModificationUuid) {
170178
// read origin group and modifications
171179
ModificationGroupEntity originModificationGroupEntity = getModificationGroup(originGroupUuid);
172180
List<ModificationEntity> originModificationEntities = originModificationGroupEntity.getModifications()
@@ -273,7 +281,7 @@ public List<ModificationInfos> getModifications(UUID groupUuid, boolean onlyMeta
273281

274282
public List<ModificationInfos> getModifications(UUID groupUuid, boolean onlyMetadata, boolean errorOnGroupNotFound, boolean onlyStashed) {
275283
try {
276-
return onlyMetadata ? getModificationsMetadata(groupUuid, onlyStashed) : getModificationsEntities(List.of(groupUuid), onlyStashed).stream().map(this::getModificationInfos).toList();
284+
return onlyMetadata ? getModificationsMetadata(groupUuid, onlyStashed) : getModificationsInfos(List.of(groupUuid), onlyStashed);
277285
} catch (NetworkModificationException e) {
278286
if (e.getType() == MODIFICATION_GROUP_NOT_FOUND && !errorOnGroupNotFound) {
279287
return List.of();
@@ -432,7 +440,7 @@ private TabularCreationInfos loadTabularCreation(ModificationEntity modification
432440
.build();
433441
}
434442

435-
public ModificationInfos getModificationInfos(ModificationEntity modificationEntity) {
443+
private ModificationInfos getModificationInfos(ModificationEntity modificationEntity) {
436444
if (modificationEntity instanceof TabularModificationEntity) {
437445
return loadTabularModification(modificationEntity);
438446
} else if (modificationEntity instanceof TabularCreationEntity) {
@@ -441,7 +449,7 @@ public ModificationInfos getModificationInfos(ModificationEntity modificationEnt
441449
return modificationEntity.toModificationInfos();
442450
}
443451

444-
public List<ModificationEntity> getModificationsEntities(List<UUID> groupUuids, boolean onlyStashed) {
452+
private List<ModificationEntity> getModificationsEntitiesNonTransactional(List<UUID> groupUuids, boolean onlyStashed) {
445453
Stream<ModificationEntity> entityStream = groupUuids.stream().flatMap(this::getModificationEntityStream);
446454
if (onlyStashed) {
447455
return entityStream.filter(m -> m.getStashed() == onlyStashed).toList();
@@ -450,6 +458,26 @@ public List<ModificationEntity> getModificationsEntities(List<UUID> groupUuids,
450458
}
451459
}
452460

461+
@Transactional(readOnly = true)
462+
public List<ModificationEntity> getModificationsEntities(List<UUID> groupUuids, boolean onlyStashed) {
463+
List<ModificationEntity> modificationsEntities = getModificationsEntitiesNonTransactional(groupUuids, onlyStashed);
464+
loadFullModificationsEntities(modificationsEntities);
465+
return modificationsEntities;
466+
}
467+
468+
private void loadFullModificationsEntities(List<ModificationEntity> modificationsEntities) {
469+
// Force load subentities/collections, needed later when the transaction is closed
470+
// Necessary for applying network modifications
471+
// to avoid LazyInitialisationException. Maybe better to refactor to return the dto ?
472+
// And refactor to more efficiently load the data (avoid 1+N) ?
473+
modificationsEntities.forEach(this::getModificationInfos);
474+
}
475+
476+
private List<ModificationInfos> getModificationsInfos(List<UUID> groupUuids, boolean onlyStashed) {
477+
return getModificationsEntitiesNonTransactional(groupUuids, onlyStashed).stream()
478+
.map(this::getModificationInfos).toList();
479+
}
480+
453481
@Transactional(readOnly = true)
454482
public ModificationInfos getModificationInfo(UUID modificationUuid) {
455483
return getModificationInfos(getModificationEntity(modificationUuid));
@@ -523,6 +551,10 @@ public Integer getModificationsCount(@NonNull UUID groupUuid, boolean stashed) {
523551

524552
@Transactional(readOnly = true)
525553
public List<ModificationInfos> getModificationsInfos(@NonNull List<UUID> uuids) {
554+
return getModificationsInfosNonTransactional(uuids);
555+
}
556+
557+
private List<ModificationInfos> getModificationsInfosNonTransactional(List<UUID> uuids) {
526558
// Spring-data findAllById doc says: the order of elements in the result is not guaranteed
527559
Map<UUID, ModificationEntity> entities = modificationRepository.findAllById(uuids)
528560
.stream()
@@ -551,6 +583,10 @@ public List<ModificationInfos> getBasicNetworkModificationsFromComposite(@NonNul
551583

552584
@Transactional(readOnly = true)
553585
public List<ModificationInfos> getCompositeModificationsInfos(@NonNull List<UUID> uuids) {
586+
return getCompositeModificationsInfosNonTransactional(uuids);
587+
}
588+
589+
private List<ModificationInfos> getCompositeModificationsInfosNonTransactional(@NonNull List<UUID> uuids) {
554590
List<ModificationInfos> entities = new ArrayList<>();
555591
uuids.forEach(uuid -> {
556592
List<UUID> foundEntities = modificationRepository.findModificationIdsByCompositeModificationId(uuid);
@@ -566,6 +602,10 @@ public List<ModificationInfos> getCompositeModificationsInfos(@NonNull List<UUID
566602

567603
@Transactional(readOnly = true)
568604
public List<ModificationInfos> getActiveModificationsInfos(@NonNull UUID groupUuid) {
605+
return getActiveModificationsInfosNonTransactional(groupUuid);
606+
}
607+
608+
private List<ModificationInfos> getActiveModificationsInfosNonTransactional(UUID groupUuid) {
569609
return getModificationEntityStream(groupUuid).filter(m -> !m.getStashed()).map(this::getModificationInfos).toList();
570610
}
571611

@@ -787,4 +827,16 @@ private void deleteTabularModificationSubModifications(TabularModificationEntity
787827
// line function works for any modification case
788828
lineModificationRepository.deleteTabularModificationModifications(modificationId, subModificationsIds);
789829
}
830+
831+
@Transactional
832+
public List<ModificationEntity> saveDuplicateModifications(@NonNull UUID targetGroupUuid, UUID originGroupUuid, @NonNull List<UUID> modificationsUuids) {
833+
List<ModificationInfos> modificationInfos = originGroupUuid != null ? getActiveModificationsInfosNonTransactional(originGroupUuid) : getModificationsInfosNonTransactional(modificationsUuids);
834+
return saveModificationInfosNonTransactional(targetGroupUuid, modificationInfos);
835+
}
836+
837+
@Transactional
838+
public List<ModificationEntity> saveCompositeModifications(@NonNull UUID targetGroupUuid, @NonNull List<UUID> modificationsUuids) {
839+
List<ModificationInfos> modificationInfos = getCompositeModificationsInfosNonTransactional(modificationsUuids);
840+
return saveModificationInfosNonTransactional(targetGroupUuid, modificationInfos);
841+
}
790842
}

src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,6 @@ public void restoreNetworkModifications(UUID groupUuid, @NonNull List<UUID> modi
191191
networkModificationRepository.getModificationsCount(groupUuid, false));
192192
}
193193

194-
// No transactional because we need to save modification in DB also in case of error
195-
// Transaction made in 'saveModifications' method
196-
// TODO Add transaction when errors will no longer be sent to the front
197194
public NetworkModificationsResult createNetworkModification(@NonNull UUID groupUuid, @NonNull ModificationInfos modificationInfo, @NonNull List<ModificationApplicationContext> applicationContexts) {
198195
List<ModificationEntity> modificationEntities = networkModificationRepository.saveModificationInfos(groupUuid, List.of(modificationInfo));
199196

@@ -237,7 +234,6 @@ public Network cloneNetworkVariant(UUID networkUuid,
237234
return network;
238235
}
239236

240-
@Transactional
241237
public NetworkModificationResult buildVariant(@NonNull UUID networkUuid, @NonNull BuildInfos buildInfos) {
242238
// Apply all modifications belonging to the modification groups uuids in buildInfos
243239
List<ModificationApplicationGroup> modificationGroupsInfos = new ArrayList<>();
@@ -246,6 +242,7 @@ public NetworkModificationResult buildVariant(@NonNull UUID networkUuid, @NonNul
246242
Set<UUID> modificationsToExclude = buildInfos.getModificationUuidsToExclude().get(groupUuid);
247243
List<ModificationEntity> modifications = List.of();
248244
try {
245+
// FullDto needed for toModificationInfos() after the modifications have been applied
249246
modifications = networkModificationRepository.getModificationsEntities(List.of(groupUuid), false)
250247
.stream()
251248
.filter(m -> modificationsToExclude == null || !modificationsToExclude.contains(m.getId()))
@@ -287,11 +284,11 @@ public void deleteNetworkModifications(UUID groupUuid, List<UUID> modificationsU
287284
}
288285
}
289286

290-
@Transactional
291287
public NetworkModificationsResult moveModifications(@NonNull UUID destinationGroupUuid, @NonNull UUID originGroupUuid, UUID beforeModificationUuid,
292288
@NonNull List<UUID> modificationsToMoveUuids, @NonNull List<ModificationApplicationContext> applicationContexts,
293289
boolean applyModifications) {
294290
// update origin/destinations groups to cut and paste all modificationsToMove
291+
// FullDto needed for toModificationInfos() after the modifications have been applied
295292
List<ModificationEntity> modificationEntities = networkModificationRepository.moveModifications(destinationGroupUuid, originGroupUuid, modificationsToMoveUuids, beforeModificationUuid);
296293

297294
List<Optional<NetworkModificationResult>> result = applyModifications && !modificationEntities.isEmpty() ? applyModifications(destinationGroupUuid, modificationEntities, applicationContexts) : List.of();
@@ -333,23 +330,19 @@ private Optional<NetworkModificationResult> applyModifications(UUID networkUuid,
333330
return Optional.empty();
334331
}
335332

336-
@Transactional
337333
public NetworkModificationsResult duplicateModifications(@NonNull UUID targetGroupUuid, UUID originGroupUuid, @NonNull List<UUID> modificationsUuids, @NonNull List<ModificationApplicationContext> applicationContexts) {
338334
if (originGroupUuid != null && !modificationsUuids.isEmpty()) { // Duplicate modifications from a group or from a list only
339335
throw new NetworkModificationServerException(DUPLICATION_ARGUMENT_INVALID);
340336
}
341-
List<ModificationInfos> modificationInfos = originGroupUuid != null ? networkModificationRepository.getActiveModificationsInfos(originGroupUuid) : networkModificationRepository.getModificationsInfos(modificationsUuids);
342-
List<ModificationEntity> duplicateModifications = networkModificationRepository.saveModificationInfos(targetGroupUuid, modificationInfos);
337+
List<ModificationEntity> duplicateModifications = networkModificationRepository.saveDuplicateModifications(targetGroupUuid, originGroupUuid, modificationsUuids);
343338
return new NetworkModificationsResult(
344339
duplicateModifications.stream().map(ModificationEntity::getId).toList(),
345340
applyModifications(targetGroupUuid, duplicateModifications, applicationContexts)
346341
);
347342
}
348343

349-
@Transactional
350344
public NetworkModificationsResult insertCompositeModifications(@NonNull UUID targetGroupUuid, @NonNull List<UUID> modificationsUuids, @NonNull List<ModificationApplicationContext> applicationContexts) {
351-
List<ModificationInfos> modificationInfos = networkModificationRepository.getCompositeModificationsInfos(modificationsUuids);
352-
List<ModificationEntity> modificationEntities = networkModificationRepository.saveModificationInfos(targetGroupUuid, modificationInfos);
345+
List<ModificationEntity> modificationEntities = networkModificationRepository.saveCompositeModifications(targetGroupUuid, modificationsUuids);
353346
return new NetworkModificationsResult(modificationEntities.stream().map(ModificationEntity::getId).toList(), applyModifications(targetGroupUuid, modificationEntities, applicationContexts));
354347
}
355348

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
Copyright (c) 2025, RTE (http://www.rte-france.com)
3+
This Source Code Form is subject to the terms of the Mozilla Public
4+
License, v. 2.0. If a copy of the MPL was not distributed with this
5+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
package org.gridsuite.modification.server.dto;
8+
9+
import org.gridsuite.modification.server.dto.catalog.LineTypeInfos;
10+
import org.junit.jupiter.api.DisplayName;
11+
import org.junit.jupiter.api.Test;
12+
13+
import java.util.UUID;
14+
15+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
16+
17+
/**
18+
* @author Achour Berrahma <achour.berrahma at rte-france.com>
19+
*/
20+
class LineTypeInfosTest {
21+
22+
@Test
23+
@DisplayName("Should throw UnsupportedOperationException when toEntity is called on base class")
24+
void testToEntityOnBaseClass() {
25+
LineTypeInfos lineTypeInfos = LineTypeInfos.builder()
26+
.id(UUID.randomUUID())
27+
.type("Generic Type")
28+
.voltage(220)
29+
.build();
30+
assertThatThrownBy(lineTypeInfos::toEntity)
31+
.isInstanceOf(UnsupportedOperationException.class)
32+
.hasMessage("toEntity() should be implemented in subclasses");
33+
}
34+
}

src/test/java/org/gridsuite/modification/server/service/BuildTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,11 @@ void testIndexationAfterBuild(final MockWebServer server) {
362362
.couplingDevices(Arrays.asList(CouplingDeviceInfos.builder().busbarSectionId1("vl9_1_1").busbarSectionId2("vl9_2_1").build()))
363363
.build()));
364364
// add new Load
365+
// Need an entity with a lazyloaded subentity/collection to test that all required
366+
// data has been loaded during the initial completed transaction before applying modifications:
367+
// LoadCreationInfos and other modifications in this test do the job because it has the free properties Collection.
368+
// Is there a good way to add in this test that we have 2 short transactions
369+
// instead of one long idle transaction ?
365370
equipmentsToAdd.add(ModificationEntity.fromDTO(LoadCreationInfos.builder()
366371
.equipmentId("newLoad")
367372
.equipmentName("newLoad")

0 commit comments

Comments
 (0)