Skip to content
Merged
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
@@ -1,17 +1,23 @@
package com.rte_france.antares.datamanager_back.repository;

import com.rte_france.antares.datamanager_back.repository.model.ThermalClusterRef;
import com.rte_france.antares.datamanager_back.repository.model.ThermalTechnology;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;
import java.util.Optional;

public interface ThermalClusterRefRepository extends JpaRepository<ThermalClusterRef, Integer> {

@Query("SELECT tcr FROM ThermalClusterRef tcr " +
"JOIN FETCH tcr.thermalTechnology tt " +
"WHERE tcr.name = ?1 AND tt.name = :name AND tt.name = :technology")
Optional<ThermalClusterRef> findByNameAndNameAndThermalTechnology(String name, String technology);
Optional<ThermalClusterRef> findByThermalTechnology_NameIgnoreCaseAndNameIgnoreCase(
String technology,
String name
);

List<ThermalClusterRef> findByThermalTechnologyIsNullAndNameIgnoreCase(String name);

List<ThermalClusterRef> findByNamePemmdbIgnoreCase(String namePemmdb);

List<ThermalClusterRef> findByNameIgnoreCase(String name);


}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Slf4j
@Service
Expand All @@ -25,109 +23,124 @@ public class ThermalClusterRefServiceImpl implements ThermalClusterRefService {
private final ThermalTechnologyRepository thermalTechnologyRepository;

/**
* Cache d'entités MANAGÉES (clé = technology + name)
* ⚠️ valide uniquement dans la transaction d'import
* Finds an existing ThermalClusterRef based on the provided parameters or creates a new one if it does not exist.
* The method ensures that the provided technology and cluster name are used to identify the ThermalClusterRef,
* while also validating and updating the PEMMDB information if required.
*
* @param technologyName the name of the thermal technology. Can be null, in which case the search is scoped accordingly.
* @param clusterName the name of the thermal cluster. It is trimmed of any leading/trailing whitespace before processing.
* @param namePemmdb the PEMMDB name associated with the cluster. It can be null or "NA" if there is no valid PEMMDB.
* @return the found or newly created ThermalClusterRef entity.
* @throws BusinessException if the given technologyName does not correspond to any existing ThermalTechnology.
*/
private Map<ClusterKey, ThermalClusterRef> cachedClusterRefs;

@Transactional
@Override
public ThermalClusterRef findOrCreateThermalClusterRef(String technology, String name, String namePemmdb) {
ensureCacheLoaded();
public ThermalClusterRef findOrCreateThermalClusterRef(String technologyName, String clusterName, String namePemmdb) {
String trimmedName = clusterName.trim();
boolean hasPemmdb = isValidPemmdb(namePemmdb);

String trimmedName = name != null ? name.trim() : null;
ClusterKey key = new ClusterKey(technology, trimmedName);
Optional<ThermalClusterRef> optionalThermalClusterRef = findExistingCluster(technologyName, trimmedName, namePemmdb, hasPemmdb);

ThermalClusterRef ref = cachedClusterRefs.get(key);
if (ref != null) {
return updatePemmdbIfNeeded(ref, namePemmdb);
if (optionalThermalClusterRef.isPresent()) {
return updatePemmdbIfNeeded(optionalThermalClusterRef.get(), namePemmdb);
}

// Création si absent
ThermalTechnology thermalTechnology = technology != null ? findThermalTechnology(technology) : null;
ThermalTechnology thermalTechnology = technologyName != null ? getThermalTechnology(technologyName) : null;
ThermalClusterRef ref = buildThermalClusterRef(namePemmdb, trimmedName, thermalTechnology);
return thermalClusterRefRepository.save(ref);
}

ref = buildClusterRef(trimmedName, thermalTechnology, namePemmdb);
thermalClusterRefRepository.save(ref);
private Optional<ThermalClusterRef> findExistingCluster(String technologyName, String trimmedName, String namePemmdb, boolean hasPemmdb) {
Optional<ThermalClusterRef> clusterRef;

cachedClusterRefs.put(key, ref);
return ref;
}
// 1. Try finding by technology and name
if (technologyName != null) {
clusterRef = findByTechnologyAndName(technologyName, trimmedName, namePemmdb, hasPemmdb);
} else {
// 2. Try finding by name with null technology
clusterRef = findByNullTechnologyAndName(trimmedName, namePemmdb, hasPemmdb);
}

// ==========================
// Cache
// ==========================
// 3. Try finding by PEMMDB if still not found
if (clusterRef.isEmpty() && hasPemmdb) {
clusterRef = findByPemmdb(technologyName, namePemmdb);
}

private void ensureCacheLoaded() {
if (cachedClusterRefs == null) {
loadAllThermalClusterRefs();
// 4. Try finding by name (any technology) as a fallback when technology is null
if (clusterRef.isEmpty() && technologyName == null) {
clusterRef = findByNameFallback(trimmedName, namePemmdb, hasPemmdb);
}

return clusterRef;
}

private void loadAllThermalClusterRefs() {
List<ThermalClusterRef> refs = thermalClusterRefRepository.findAll();
Map<ClusterKey, ThermalClusterRef> map = new HashMap<>();
private Optional<ThermalClusterRef> findByTechnologyAndName(String technologyName, String trimmedName, String namePemmdb, boolean hasPemmdb) {
return thermalClusterRefRepository.findByThermalTechnology_NameIgnoreCaseAndNameIgnoreCase(technologyName, trimmedName)
.filter(ref -> matchesPemmdb(ref, namePemmdb, hasPemmdb));
}

for (ThermalClusterRef ref : refs) {
String techName = ref.getThermalTechnology() != null ? ref.getThermalTechnology().getName() : null;
private Optional<ThermalClusterRef> findByNullTechnologyAndName(String trimmedName, String namePemmdb, boolean hasPemmdb) {
List<ThermalClusterRef> techNullRefs = thermalClusterRefRepository.findByThermalTechnologyIsNullAndNameIgnoreCase(trimmedName);
return techNullRefs.stream()
.filter(ref -> matchesPemmdb(ref, namePemmdb, hasPemmdb))
.findFirst();
}

map.put(new ClusterKey(techName, ref.getName()), ref);
private Optional<ThermalClusterRef> findByPemmdb(String technologyName, String namePemmdb) {
List<ThermalClusterRef> pemmdbRefs = thermalClusterRefRepository.findByNamePemmdbIgnoreCase(namePemmdb.trim());
if (pemmdbRefs.size() == 1) {
return Optional.of(pemmdbRefs.get(0));
} else if (pemmdbRefs.size() > 1 && technologyName != null) {
return pemmdbRefs.stream()
.filter(r -> r.getThermalTechnology() != null && r.getThermalTechnology().getName().equalsIgnoreCase(technologyName))
.findFirst();
}
cachedClusterRefs = map;
return Optional.empty();
}

// ==========================
// Helpers
// ==========================

private ThermalClusterRef updatePemmdbIfNeeded(ThermalClusterRef ref, String namePemmdb) {
if (namePemmdb != null && !namePemmdb.isBlank()) {
String current = ref.getNamePemmdb();
if (current == null || current.isBlank() || "NA".equalsIgnoreCase(current)) {
ref.setNamePemmdb(namePemmdb);
private Optional<ThermalClusterRef> findByNameFallback(String trimmedName, String namePemmdb, boolean hasPemmdb) {
List<ThermalClusterRef> refs = thermalClusterRefRepository.findByNameIgnoreCase(trimmedName);
ThermalClusterRef found = null;
for (ThermalClusterRef ref : refs) {
if (matchesPemmdb(ref, namePemmdb, hasPemmdb)) {
if (found == null) {
found = ref;
} else {
return Optional.empty(); // Ambiguous
}
}
}
return ref;
}

private ThermalTechnology findThermalTechnology(String technology) {
return thermalTechnologyRepository.findThermalTechnologyByNameIgnoreCase(technology)
.orElseThrow(() -> BusinessException.builder().message("Technology {0} does not exist in the technology reference table.")
.errorMessageArguments(Collections.singletonList(technology))
.build());
return Optional.ofNullable(found);
}

private ThermalClusterRef buildClusterRef(String name, ThermalTechnology technology, String namePemmdb) {
return ThermalClusterRef.builder()
.name(name).thermalTechnology(technology).namePemmdb((namePemmdb != null && !namePemmdb.isBlank()) ? namePemmdb : "NA")
.build();
private boolean isValidPemmdb(String namePemmdb) {
return namePemmdb != null && !namePemmdb.isBlank() && !"NA".equalsIgnoreCase(namePemmdb.trim());
}

// ==========================
// Key
// ==========================

private record ClusterKey(String technology, String name) {
private boolean matchesPemmdb(ThermalClusterRef ref, String namePemmdb, boolean hasPemmdb) {
String refPemmdb = ref.getNamePemmdb();
boolean refHasPemmdb = isValidPemmdb(refPemmdb);

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ClusterKey other)) return false;
return equalsIgnoreCase(technology, other.technology) && equalsIgnoreCase(name, other.name);
if (hasPemmdb != refHasPemmdb) {
return false;
}
return !hasPemmdb || refPemmdb.trim().equalsIgnoreCase(namePemmdb.trim());
}

@Override
public int hashCode() {
return (normalize(technology) + "|" + normalize(name)).hashCode();
}
private ThermalTechnology getThermalTechnology(String technologyName) {
return thermalTechnologyRepository.findThermalTechnologyByNameIgnoreCase(technologyName).orElseThrow(() -> BusinessException.builder().message("Technology " + technologyName + " does not exist").build());
}

private static boolean equalsIgnoreCase(String a, String b) {
if (a == null && b == null) return true;
if (a == null || b == null) return false;
return a.equalsIgnoreCase(b);
}
private static ThermalClusterRef buildThermalClusterRef(String namePemmdb, String trimmedName, ThermalTechnology technology) {
return ThermalClusterRef.builder().name(trimmedName).namePemmdb(namePemmdb != null && !namePemmdb.isBlank() ? namePemmdb : "NA").thermalTechnology(technology).build();
}

private static String normalize(String s) {
return s == null ? "" : s.toLowerCase();
private ThermalClusterRef updatePemmdbIfNeeded(ThermalClusterRef ref, String namePemmdb) {
if (namePemmdb != null && !namePemmdb.isBlank()) {
String current = ref.getNamePemmdb();
if (current == null || current.isBlank() || "NA".equalsIgnoreCase(current)) {
ref.setNamePemmdb(namePemmdb);
}
}
return ref;
}
}
Loading