Compare commits

..

2 Commits

Author SHA1 Message Date
marcus 4bbee57d41 Fix #58: Verschluckte Exception in ResolveHistoricalFileName loggen
Catch von Exception auf RuntimeException eingeengt; unerwartete
Laufzeitfehler werden jetzt per logger.warn() protokolliert und
weiterpropagiert statt still verschluckt zu werden.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 15:43:52 +02:00
marcus 43c54923f8 Fix #57: Verschluckte Exception in ResolveHistoricalDocumentContext loggen
Log4j2-API als Abhaengigkeit im Application-Modul ergaenzt. Catch von
Exception auf RuntimeException eingeengt; unerwartete Laufzeitfehler
werden jetzt per logger.warn() protokolliert und weiterpropagiert statt
still verschluckt zu werden.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 15:43:45 +02:00
3 changed files with 41 additions and 16 deletions
+6
View File
@@ -19,6 +19,12 @@
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<!-- Logging API (nur API, keine Implementierung gebunden durch Bootstrap) -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<!-- JSON parsing for AI response parsing --> <!-- JSON parsing for AI response parsing -->
<dependency> <dependency>
<groupId>org.json</groupId> <groupId>org.json</groupId>
@@ -3,6 +3,9 @@ package de.gecheckt.pdf.umbenenner.application.usecase;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.gecheckt.pdf.umbenenner.application.port.in.HistoricalDocumentContext; import de.gecheckt.pdf.umbenenner.application.port.in.HistoricalDocumentContext;
import de.gecheckt.pdf.umbenenner.application.port.in.ResolveHistoricalDocumentContextUseCase; import de.gecheckt.pdf.umbenenner.application.port.in.ResolveHistoricalDocumentContextUseCase;
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecordLookupResult; import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecordLookupResult;
@@ -22,15 +25,20 @@ import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint;
* Stammsatz ({@code lastTargetFileName}, {@code lastSuccessInstant}).</li> * Stammsatz ({@code lastTargetFileName}, {@code lastSuccessInstant}).</li>
* <li>Bei endgültigem Fehlschlag: Fehlzeitpunkt aus dem Stammsatz * <li>Bei endgültigem Fehlschlag: Fehlzeitpunkt aus dem Stammsatz
* ({@code lastFailureInstant}).</li> * ({@code lastFailureInstant}).</li>
* <li>In allen anderen Fällen (unbekannt, verarbeitbar) sowie bei technischen * <li>In allen anderen Fällen (unbekannt, verarbeitbar) sowie bei erwarteten technischen
* Abfragefehlern: leeres {@link Optional}.</li> * Abfragefehlern: leeres {@link Optional}.</li>
* </ul> * </ul>
* Technische Fehler bei der Repository-Abfrage werden intern abgefangen; der Aufrufer * Unerwartete {@link RuntimeException}s aus dem Repository werden geloggt (WARN) und
* erhält stets ein leeres Ergebnis statt einer Ausnahme. * weiterpropagiert. Erwartete Lookup-Fehler werden als
* {@code PersistenceLookupTechnicalFailure} im Rückgabewert kodiert und führen
* zu einem leeren {@link Optional}.
*/ */
public class DefaultResolveHistoricalDocumentContextUseCase public class DefaultResolveHistoricalDocumentContextUseCase
implements ResolveHistoricalDocumentContextUseCase { implements ResolveHistoricalDocumentContextUseCase {
private static final Logger logger =
LogManager.getLogger(DefaultResolveHistoricalDocumentContextUseCase.class);
private final DocumentRecordRepository documentRecordRepository; private final DocumentRecordRepository documentRecordRepository;
/** /**
@@ -76,8 +84,10 @@ public class DefaultResolveHistoricalDocumentContextUseCase
failure.record().lastFailureInstant())); failure.record().lastFailureInstant()));
} }
return Optional.empty(); return Optional.empty();
} catch (Exception e) { } catch (RuntimeException e) {
return Optional.empty(); logger.warn("Unerwarteter Fehler beim Lesen des Dokument-Stammsatzes für Fingerprint {}: {}",
fingerprint, e.getMessage(), e);
throw e;
} }
} }
} }
@@ -3,6 +3,9 @@ package de.gecheckt.pdf.umbenenner.application.usecase;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import de.gecheckt.pdf.umbenenner.application.port.in.ResolveHistoricalFileNameUseCase; import de.gecheckt.pdf.umbenenner.application.port.in.ResolveHistoricalFileNameUseCase;
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecordLookupResult; import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecordLookupResult;
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecordRepository; import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecordRepository;
@@ -10,20 +13,24 @@ import de.gecheckt.pdf.umbenenner.application.port.out.DocumentTerminalSuccess;
import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint; import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint;
/** /**
* Default implementation of {@link ResolveHistoricalFileNameUseCase}. * Standardimplementierung von {@link ResolveHistoricalFileNameUseCase}.
* <p> * <p>
* Queries the {@link DocumentRecordRepository} for the master record of the given fingerprint. * Fragt den {@link DocumentRecordRepository} nach dem Stammsatz des angegebenen
* If the record represents a document that previously reached a successful terminal state, * Fingerprints ab. Ist der Stammsatz terminal erfolgreich, wird der zuletzt
* the last known target filename ({@code lastTargetFileName}) is returned. * geschriebene Zieldateiname zurückgegeben.
* <p> * <p>
* For all other terminal states (e.g. documents that finally failed without ever producing * Für alle anderen terminalen Zustände oder wenn kein Stammsatz vorhanden ist,
* a target copy) or when no master record exists, an empty {@link Optional} is returned. * wird ein leeres {@link Optional} zurückgegeben.
* Technical failures during the repository lookup are caught silently and treated as * Unerwartete {@link RuntimeException}s aus dem Repository werden geloggt (WARN) und
* an absent result so that the calling GUI layer is never forced to handle exceptions * weiterpropagiert. Erwartete Lookup-Fehler werden als
* from this query path. * {@code PersistenceLookupTechnicalFailure} im Rückgabewert kodiert und führen
* zu einem leeren {@link Optional}.
*/ */
public class DefaultResolveHistoricalFileNameUseCase implements ResolveHistoricalFileNameUseCase { public class DefaultResolveHistoricalFileNameUseCase implements ResolveHistoricalFileNameUseCase {
private static final Logger logger =
LogManager.getLogger(DefaultResolveHistoricalFileNameUseCase.class);
private final DocumentRecordRepository documentRecordRepository; private final DocumentRecordRepository documentRecordRepository;
/** /**
@@ -62,8 +69,10 @@ public class DefaultResolveHistoricalFileNameUseCase implements ResolveHistorica
return Optional.ofNullable(success.record().lastTargetFileName()); return Optional.ofNullable(success.record().lastTargetFileName());
} }
return Optional.empty(); return Optional.empty();
} catch (Exception e) { } catch (RuntimeException e) {
return Optional.empty(); logger.warn("Unerwarteter Fehler beim Lesen des historischen Dateinamens für Fingerprint {}: {}",
fingerprint, e.getMessage(), e);
throw e;
} }
} }
} }