164 lines
6.2 KiB
Java
164 lines
6.2 KiB
Java
/**
|
|
* Enterprise Change Tracking Service
|
|
* Demonstrates advanced Java patterns and Spring Boot integration
|
|
*/
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class ChangeTrackingService {
|
|
|
|
private final VersionChangesService versionChangesService;
|
|
private final SomeListService someListService;
|
|
|
|
// Thread-safe change collection
|
|
private List<VersionChange> changes;
|
|
private Map<String, someDto> referenceDataCache;
|
|
|
|
/**
|
|
* Main entry point - demonstrates clean API design and comprehensive change detection
|
|
*/
|
|
public List<VersionChange> trackChanges(
|
|
EmissionDataDto oldVersion,
|
|
EmissionDataDto newVersion,
|
|
boolean isRegulationAVV,
|
|
boolean isRegulationEEV) {
|
|
|
|
// Initialize tracking context with immutable metadata
|
|
initializeTrackingContext(oldVersion, newVersion);
|
|
|
|
loadReferenceData(newVersion.getReportingYear());
|
|
|
|
// Modular comparison strategy - each method handles specific data domain
|
|
compareBasicData(oldVersion, newVersion);
|
|
compareFuelData(oldVersion.getFuels(), newVersion.getFuels(), isRegulationEEV);
|
|
compareEmissionData(oldVersion, newVersion, isRegulationAVV, isRegulationEEV);
|
|
compareDocuments(oldVersion.getDocuments(), newVersion.getDocuments());
|
|
|
|
return persistChanges();
|
|
}
|
|
|
|
/**
|
|
* Demonstrates collection comparison with UUID-based matching
|
|
*/
|
|
private void compareFuelData(List<FuelDto> oldFuels, List<FuelDto> newFuels, boolean isSomething) {
|
|
// Track removed items using functional programming approach
|
|
oldFuels.stream()
|
|
.filter(oldFuel -> newFuels.stream()
|
|
.noneMatch(newFuel -> newFuel.getUuid().equals(oldFuel.getUuid())))
|
|
.forEach(removedFuel -> trackChange(
|
|
"FUEL",
|
|
"REMOVED: " + resolveFuelName(removedFuel),
|
|
null,
|
|
"REMOVED",
|
|
"FUELS",
|
|
"FUEL_MANAGEMENT"
|
|
));
|
|
|
|
// Compare existing and new items with detailed field-level tracking
|
|
newFuels.forEach(newFuel -> {
|
|
FuelDto oldFuel = findMatchingFuel(oldFuels, newFuel.getUuid());
|
|
|
|
if (oldFuel == null) {
|
|
trackNewFuel(newFuel);
|
|
} else {
|
|
compareFuelFields(oldFuel, newFuel, isSomething);
|
|
compareMonthlyValues(oldFuel, newFuel);
|
|
compareMassComponents(oldFuel.getComponents(), newFuel.getComponents());
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Field comparison with null-safe operations and type-specific handling
|
|
*/
|
|
private void compareFuelFields(FuelDto oldFuel, FuelDto newFuel, boolean isSomething) {
|
|
String fuelLabel = resolveFuelName(newFuel);
|
|
|
|
// BigDecimal comparison with precision handling
|
|
if (!Objects.equals(oldFuel.getCalorificValue(), newFuel.getCalorificValue())) {
|
|
trackChange("FUEL", fuelLabel + " - Calorific Value",
|
|
oldFuel.getCalorificValue(), newFuel.getCalorificValue(),
|
|
"FUELS", "FUEL_PROPERTIES");
|
|
}
|
|
|
|
// Date comparison with custom formatting
|
|
if (!areDatesEqual(oldFuel.getLastModified(), newFuel.getLastModified())) {
|
|
trackChange("FUEL", fuelLabel + " - Last Modified",
|
|
formatDate(oldFuel.getLastModified()),
|
|
formatDate(newFuel.getLastModified()),
|
|
"FUELS", "FUEL_METADATA");
|
|
}
|
|
|
|
if (isSomething) {
|
|
compareEEVSpecificFields(oldFuel, newFuel, fuelLabel);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Demonstrates intelligent reference data resolution with fallback strategies
|
|
*/
|
|
private String resolveFuelName(FuelDto fuel) {
|
|
return Optional.ofNullable(referenceDataCache.get(fuel.getGtin()))
|
|
.map(someDto::getDisplayName)
|
|
.orElse(Optional.ofNullable(fuel.getCustomName())
|
|
.orElse("Unknown Fuel [" + fuel.getGtin() + "]"));
|
|
}
|
|
|
|
/**
|
|
* Error-resilient reference data loading with graceful degradation
|
|
*/
|
|
private void loadReferenceData(String reportingYear) {
|
|
try {
|
|
this.referenceDataCache = someListService.getFuelTypes(reportingYear, false);
|
|
} catch (HibernateException | DBException e) {
|
|
log.warn("Reference data unavailable, using fallback strategy", e);
|
|
this.referenceDataCache = new HashMap<>();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Immutable change record creation with comprehensive metadata
|
|
*/
|
|
private void trackChange(String tableName, String fieldName,
|
|
Object oldValue, Object newValue,
|
|
String formPage, String blockName) {
|
|
|
|
changes.add(VersionChange.builder()
|
|
.rootRef(this.rootRef)
|
|
.oldVersion(this.oldVersion)
|
|
.newVersion(this.newVersion)
|
|
.tableName(tableName)
|
|
.fieldName(fieldName)
|
|
.oldValue(formatValue(oldValue))
|
|
.newValue(formatValue(newValue))
|
|
.formPage(formPage)
|
|
.blockName(blockName)
|
|
.timestamp(Instant.now())
|
|
.userGln(this.userGln)
|
|
.build());
|
|
}
|
|
|
|
/**
|
|
* Type-safe value formatting with polymorphic handling
|
|
*/
|
|
private String formatValue(Object value) {
|
|
return switch (value) {
|
|
case null -> null;
|
|
case Date date -> dateFormatter.format(date);
|
|
case BigDecimal decimal -> decimal.toPlainString();
|
|
case Boolean bool -> bool ? "Yes" : "No";
|
|
default -> value.toString();
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Ppersistence with Spring transaction management
|
|
*/
|
|
@Transactional
|
|
private List<VersionChange> persistChanges() {
|
|
if (!changes.isEmpty()) {
|
|
versionChangesService.saveAll(changes);
|
|
log.info("Persisted {} changes for version {}", changes.size(), newVersion);
|
|
}
|
|
return List.copyOf(changes); // Return immutable copy
|
|
}
|
|
} |