Bugfix V3.2: RunLockPort-JavaDoc korrigiert und Backup-Fehler bei aktivem Scheduler behoben

BUG 1: RunLockPort-JavaDoc dokumentierte den Scheduler-Tick faelschlicherweise als
nicht-blockierenden Pfad mit tryAcquire(). Da execute() intern acquire() aufruft,
wuerde tryAcquire() vor execute() einen Double-Lock erzeugen. JavaDoc korrigiert:
Scheduler-Tick nutzt denselben blockierenden acquire()-Pfad wie der manuelle Lauf.

BUG 2: GuiConfigurationPropertiesWriter.copyFile() faengt jetzt AccessDeniedException
separat ab und liefert den klaren Hinweis "Konfiguration kann nicht gespeichert
werden - Scheduler laeuft." statt einer generischen Fehlermeldung.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 12:14:43 +02:00
parent 4bc70dae75
commit 719cc50d16
2 changed files with 11 additions and 7 deletions
@@ -16,18 +16,18 @@ import java.util.Optional;
* <li>Kontrollierten Startabbruch ermöglichen, wenn bereits eine Instanz läuft</li> * <li>Kontrollierten Startabbruch ermöglichen, wenn bereits eine Instanz läuft</li>
* </ul> * </ul>
* <p> * <p>
* Lock-Lifecycle (blockierender Pfad headless und manueller GUI-Lauf): * Lock-Lifecycle (blockierender Pfad headless, manueller GUI-Lauf und Scheduler-Tick):
* <ol> * <ol>
* <li>Lock beim Laufstart erwerben ({@link #acquire()})</li> * <li>Lock beim Laufstart erwerben ({@link #acquire()})</li>
* <li>Lock für die gesamte Dauer des Laufs halten</li> * <li>Lock für die gesamte Dauer des Laufs halten</li>
* <li>Lock am Laufende freigeben ({@link #release()}), auch bei Fehler</li> * <li>Lock am Laufende freigeben ({@link #release()}), auch bei Fehler</li>
* </ol> * </ol>
* Lock-Lifecycle (nicht-blockierender Pfad Scheduler-Tick): * Der Scheduler-Tick verwendet dieselbe blockierende Methode {@link #acquire()} wie
* <ol> * der manuelle Laufpfad. {@link BatchRunProcessingUseCase#execute execute()} ruft
* <li>Lock nicht-blockierend versuchen ({@link #tryAcquire()})</li> * {@link #acquire()} intern auf; das Ergebnis {@code LOCK_UNAVAILABLE} signalisiert
* <li>Bei leerem Optional sofort mit {@code SkippedBusy} abbrechen</li> * dem Aufrufer, dass ein paralleler Lauf aktiv ist.
* <li>Bei vorhandenem Handle in try-with-resources verwenden</li> * {@link #tryAcquire()} ist für Aufrufer vorgesehen, die außerhalb des Use-Case
* </ol> * einen schnellen, nicht-blockierenden Lock-Versuch benötigen.
*/ */
public interface RunLockPort { public interface RunLockPort {
@@ -2,6 +2,7 @@ package de.gecheckt.pdf.umbenenner.bootstrap.adapter;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.AccessDeniedException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
@@ -156,6 +157,9 @@ public final class GuiConfigurationPropertiesWriter implements GuiConfigurationF
private void copyFile(Path source, Path destination) { private void copyFile(Path source, Path destination) {
try { try {
Files.copy(source, destination); Files.copy(source, destination);
} catch (AccessDeniedException e) {
throw new GuiConfigurationWriteException(
"Konfiguration kann nicht gespeichert werden Scheduler läuft.", e);
} catch (IOException e) { } catch (IOException e) {
throw new GuiConfigurationWriteException( throw new GuiConfigurationWriteException(
"Sicherungskopie konnte nicht erstellt werden: " + destination, e); "Sicherungskopie konnte nicht erstellt werden: " + destination, e);