#89 #90: Log-Verzeichnis-Prüfpunkt + betrieb.md MSI-Pfadwarnungen

#90: Neuer technischer Prüfpunkt LOG_DIRECTORY_USABLE (12. Checkpoint):
- Zeigt konfigurierten log.directory-Wert und aufgelösten absoluten Pfad
- Prüft ob Verzeichnis beschreibbar/anlegbar ist (WARNING, kein ERROR)
- Liest tatsächlichen Log-Datei-Pfad via Log4j2 LoggerContext → RollingFileAppender
- LogDiagnosticsPort als neuer Outbound-Port (application-Modul)
- Log4jLogDiagnosticsAdapter als Implementierung im bootstrap-Modul
- TechnicalTestRequest erhält logDirectory-Feld
- GuiTechnicalTestCoordinator erhält logDirectoryProvider-Supplier

#89: docs/betrieb.md – MSI-Betrieb um Pfadwarnungen erweitert:
- Warnung: relative Pfade lösen sich in schreibgeschütztes C:\Program Files\ auf
- Warnung: Backslashes in .properties werden als Java-Escape-Sequenzen interpretiert
- Betroffene Parameter mit Empfehlung zu absoluten Forward-Slash-Pfaden
- Beschreibung des neuen Log-Verzeichnis-Prüfpunkts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-04 17:02:51 +02:00
parent bd2be347f6
commit 479d176536
23 changed files with 376 additions and 88 deletions
@@ -495,6 +495,7 @@ public final class GuiConfigurationEditorWorkspace {
() -> editorState.loadedFileSnapshot()
.map(snapshot -> snapshot.filePath().toString())
.orElse(""),
() -> editorState.values().logDirectory(),
pendingMessages,
report -> {
technicalTestsButton.setDisable(false);
@@ -344,7 +344,8 @@ public record GuiStartupContext(
TechnicalTestOrchestrator noOpOrchestrator = new TechnicalTestOrchestrator(
new de.gecheckt.pdf.umbenenner.application.validation.editor.EditorConfigurationValidator(),
noOpPathCheckPort,
noOpTestService);
noOpTestService,
() -> java.util.Optional.empty());
ResourceCreationPort noOpResourceCreationPort = new ResourceCreationPort() {
@Override
public de.gecheckt.pdf.umbenenner.application.validation.technicaltest.CorrectionOutcome
@@ -64,6 +64,7 @@ public final class GuiTechnicalTestCoordinator {
private final TechnicalTestOrchestrator orchestrator;
private final Supplier<EditorValidationInput> inputProvider;
private final Supplier<String> configFilePathProvider;
private final Supplier<String> logDirectoryProvider;
private final List<GuiMessageEntry> pendingMessages;
private final Consumer<TechnicalTestReport> postResultCallback;
@@ -89,6 +90,9 @@ public final class GuiTechnicalTestCoordinator {
* @param configFilePathProvider Lieferant des aktuell geladenen Konfigurationsdateipfads als String;
* gibt eine leere Zeichenkette zurück wenn keine Datei geladen ist;
* darf nicht {@code null} sein
* @param logDirectoryProvider Lieferant des konfigurierten {@code log.directory}-Rohwerts;
* gibt eine leere Zeichenkette zurück wenn kein Wert konfiguriert ist;
* darf nicht {@code null} sein
* @param pendingMessages geteilte veränderliche Nachrichtenliste; darf nicht {@code null} sein
* @param postResultCallback Callback nach erfolgreicher Ergebnisanwendung; darf nicht {@code null} sein
* @throws NullPointerException wenn einer der Parameter {@code null} ist
@@ -96,11 +100,13 @@ public final class GuiTechnicalTestCoordinator {
public GuiTechnicalTestCoordinator(TechnicalTestOrchestrator orchestrator,
Supplier<EditorValidationInput> inputProvider,
Supplier<String> configFilePathProvider,
Supplier<String> logDirectoryProvider,
List<GuiMessageEntry> pendingMessages,
Consumer<TechnicalTestReport> postResultCallback) {
this.orchestrator = Objects.requireNonNull(orchestrator, "orchestrator must not be null");
this.inputProvider = Objects.requireNonNull(inputProvider, "inputProvider must not be null");
this.configFilePathProvider = Objects.requireNonNull(configFilePathProvider, "configFilePathProvider must not be null");
this.logDirectoryProvider = Objects.requireNonNull(logDirectoryProvider, "logDirectoryProvider must not be null");
this.pendingMessages = Objects.requireNonNull(pendingMessages, "pendingMessages must not be null");
this.postResultCallback = Objects.requireNonNull(postResultCallback, "postResultCallback must not be null");
this.testThreadFactory = task -> {
@@ -134,7 +140,8 @@ public final class GuiTechnicalTestCoordinator {
pendingMessages.clear();
EditorValidationInput input = inputProvider.get();
String configFilePath = configFilePathProvider.get();
TechnicalTestRequest request = new TechnicalTestRequest(input, configFilePath);
String logDirectory = logDirectoryProvider.get();
TechnicalTestRequest request = new TechnicalTestRequest(input, configFilePath, logDirectory);
LOG.info("GUI-Gesamttest: Technische Tests ausführen gestartet.");
@@ -234,6 +241,7 @@ public final class GuiTechnicalTestCoordinator {
case SOURCE_FOLDER_PRESENT -> "Quellordner vorhanden und lesbar";
case TARGET_FOLDER_USABLE -> "Zielordner vorhanden oder anlegbar sowie schreibbar";
case SQLITE_PATH_USABLE -> "SQLite-Pfad technisch nutzbar";
case LOG_DIRECTORY_USABLE -> "Log-Verzeichnis beschreibbar";
};
}