Bugfix: alle GUI-Pfade ueberspringen Migration bei stehendem Run-Kontext

Konsequente Anwendung des Fix-Musters auf alle GUI-Methoden, die nach
dem Aufbau des ApplicationRunContext eine erneute, redundante
Legacy-Migration ausgeloest haetten. Bei aktivem Scheduler-Lock ist der
Lese-/Schreibzugriff auf die Konfigurationsdatei sonst blockiert.

Neue Helper-Methode migrateConfigurationIfNeededForGui kapselt den Check
auf den Run-Kontext und ersetzt den unbedingten Aufruf in:
- performGuiManualFileRename
- performGuiManualFileCopy
- resolveHistoricalDocumentContextForGui
- loadHistoryOverviewForGui (vorhandene inline-Variante zentralisiert)
- loadHistoryDetailsForGui
- resetHistoryDocumentStatusForGui
- deleteDocumentHistoryForGui

Die uebrigen Aufrufstellen bleiben unveraendert: der headless-Pfad,
initializeApplicationRunContext (die einzige zustaendige Stelle), die
GUI-Launch-Methoden mit bestehendem Early-Return bei vorhandenem Kontext
sowie die Stellen, die vor Aufbau des Kontexts laufen.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 13:58:51 +02:00
parent fdfc36afb7
commit ef985fb6af
@@ -1725,7 +1725,7 @@ public class BootstrapRunner {
}
try {
migrateConfigurationIfNeeded(configFilePath);
migrateConfigurationIfNeededForGui(configFilePath);
StartConfiguration config = loadAndValidateConfiguration(configFilePath);
initializeSchema(config);
ManualFileRenameUseCase useCase = buildProductionManualFileRenameUseCase(config);
@@ -1789,7 +1789,7 @@ public class BootstrapRunner {
}
try {
migrateConfigurationIfNeeded(configFilePath);
migrateConfigurationIfNeededForGui(configFilePath);
StartConfiguration config = loadAndValidateConfiguration(configFilePath);
initializeSchema(config);
ManualFileCopyUseCase useCase = buildProductionManualFileCopyUseCase(config);
@@ -1851,7 +1851,7 @@ public class BootstrapRunner {
}
try {
migrateConfigurationIfNeeded(configFilePath);
migrateConfigurationIfNeededForGui(configFilePath);
StartConfiguration config = loadAndValidateConfiguration(configFilePath);
initializeSchema(config);
String jdbcUrl = resolveActiveJdbcUrl(config);
@@ -1884,13 +1884,7 @@ public class BootstrapRunner {
Objects.requireNonNull(configFilePath, CONFIG_FILE_NOT_NULL);
Objects.requireNonNull(query, "query must not be null");
try {
// Migration nur durchführen, wenn der Anwendungskontext noch nicht steht.
// Steht er bereits, wurde die Migration in initializeApplicationRunContext
// schon einmal abgeschlossen; ein erneuter Lese-/Schreibversuch auf der
// Konfigurationsdatei kollidiert mit einem aktiven Scheduler-Lock.
if (guiApplicationRunContext.isEmpty()) {
migrateConfigurationIfNeeded(configFilePath);
}
migrateConfigurationIfNeededForGui(configFilePath);
StartConfiguration config = loadAndValidateConfiguration(configFilePath);
initializeSchema(config);
String jdbcUrl = resolveActiveJdbcUrl(config);
@@ -1920,7 +1914,7 @@ public class BootstrapRunner {
Objects.requireNonNull(configFilePath, CONFIG_FILE_NOT_NULL);
Objects.requireNonNull(fingerprint, FINGERPRINT_NOT_NULL);
try {
migrateConfigurationIfNeeded(configFilePath);
migrateConfigurationIfNeededForGui(configFilePath);
StartConfiguration config = loadAndValidateConfiguration(configFilePath);
initializeSchema(config);
String jdbcUrl = resolveActiveJdbcUrl(config);
@@ -1951,7 +1945,7 @@ public class BootstrapRunner {
Objects.requireNonNull(fingerprint, FINGERPRINT_NOT_NULL);
LOG.info("Historien-Status-Reset für Fingerprint: {}", fingerprint.sha256Hex());
try {
migrateConfigurationIfNeeded(configFilePath);
migrateConfigurationIfNeededForGui(configFilePath);
StartConfiguration config = loadAndValidateConfiguration(configFilePath);
initializeSchema(config);
String jdbcUrl = resolveActiveJdbcUrl(config);
@@ -1983,7 +1977,7 @@ public class BootstrapRunner {
Objects.requireNonNull(fingerprint, FINGERPRINT_NOT_NULL);
LOG.info("Historien-Löschen für Fingerprint: {}", fingerprint.sha256Hex());
try {
migrateConfigurationIfNeeded(configFilePath);
migrateConfigurationIfNeededForGui(configFilePath);
StartConfiguration config = loadAndValidateConfiguration(configFilePath);
initializeSchema(config);
String jdbcUrl = resolveActiveJdbcUrl(config);
@@ -2163,6 +2157,23 @@ public class BootstrapRunner {
migrationStep.runIfNeeded(effectiveConfigPath);
}
/**
* Führt die Legacy-Migration nur durch, wenn der GUI-Anwendungskontext noch nicht steht.
* <p>
* Steht der Kontext bereits, wurde die Migration in
* {@link #initializeApplicationRunContext(Path)} schon einmal abgeschlossen. Ein erneuter
* Lese-/Schreibzugriff auf die Konfigurationsdatei ist nicht nur redundant, sondern
* kollidiert auch mit einem aktiven Scheduler-Lock auf derselben Datei und führt
* dann zu {@code IOException: Datei gesperrt}.
*
* @param configFilePath Pfad zur Konfigurationsdatei; darf nicht {@code null} sein
*/
private void migrateConfigurationIfNeededForGui(Path configFilePath) {
if (guiApplicationRunContext.isEmpty()) {
migrateConfigurationIfNeeded(configFilePath);
}
}
/**
* Loads configuration from the effective configuration path and validates it.
* <p>