Files
Change-Tracking-System/Change-Tracking-Demo.java
Kasun Jayatilaka 3bc2fdf525 Upload files to "/"
added demo for change tracking system
2025-09-08 01:38:14 +02:00

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
}
}