diff --git a/pdf-umbenenner-adapter-out/src/main/java/de/gecheckt/pdf/umbenenner/adapter/out/fingerprint/Sha256FingerprintAdapter.java b/pdf-umbenenner-adapter-out/src/main/java/de/gecheckt/pdf/umbenenner/adapter/out/fingerprint/Sha256FingerprintAdapter.java index 23713fc..12f38d5 100644 --- a/pdf-umbenenner-adapter-out/src/main/java/de/gecheckt/pdf/umbenenner/adapter/out/fingerprint/Sha256FingerprintAdapter.java +++ b/pdf-umbenenner-adapter-out/src/main/java/de/gecheckt/pdf/umbenenner/adapter/out/fingerprint/Sha256FingerprintAdapter.java @@ -78,25 +78,20 @@ public class Sha256FingerprintAdapter implements FingerprintPort { return new FingerprintSuccess(fingerprint); } catch (IOException e) { - String errorMsg = String.format("Failed to read file for '%s': %s", + String errorMsg = String.format("Failed to read file for '%s': %s", candidate.uniqueIdentifier(), e.getMessage()); logger.warn(errorMsg, e); return new FingerprintTechnicalError(errorMsg, e); } catch (InvalidPathException e) { - String errorMsg = String.format("Invalid file path for '%s': %s", + String errorMsg = String.format("Invalid file path for '%s': %s", candidate.uniqueIdentifier(), e.getMessage()); logger.warn(errorMsg, e); return new FingerprintTechnicalError(errorMsg, e); } catch (NoSuchAlgorithmException e) { - String errorMsg = String.format("SHA-256 algorithm not available for '%s'", + String errorMsg = String.format("SHA-256 algorithm not available for '%s'", candidate.uniqueIdentifier()); logger.error(errorMsg, e); return new FingerprintTechnicalError(errorMsg, e); - } catch (Exception e) { - String errorMsg = String.format("Unexpected error computing fingerprint for '%s': %s", - candidate.uniqueIdentifier(), e.getMessage()); - logger.error(errorMsg, e); - return new FingerprintTechnicalError(errorMsg, e); } } diff --git a/pdf-umbenenner-adapter-out/src/main/java/de/gecheckt/pdf/umbenenner/adapter/out/sqlite/SqliteUnitOfWorkAdapter.java b/pdf-umbenenner-adapter-out/src/main/java/de/gecheckt/pdf/umbenenner/adapter/out/sqlite/SqliteUnitOfWorkAdapter.java index ea09a29..bf39e65 100644 --- a/pdf-umbenenner-adapter-out/src/main/java/de/gecheckt/pdf/umbenenner/adapter/out/sqlite/SqliteUnitOfWorkAdapter.java +++ b/pdf-umbenenner-adapter-out/src/main/java/de/gecheckt/pdf/umbenenner/adapter/out/sqlite/SqliteUnitOfWorkAdapter.java @@ -49,8 +49,19 @@ public class SqliteUnitOfWorkAdapter implements UnitOfWorkPort { connection.commit(); logger.debug("Transaction committed successfully"); - } catch (Exception e) { - // Rollback for ANY exception, not just SQLException + } catch (DocumentPersistenceException e) { + // Re-throw document-level persistence errors as-is, but still rollback + if (connection != null) { + try { + connection.rollback(); + logger.debug("Transaction rolled back due to document error: {}", e.getMessage()); + } catch (SQLException rollbackEx) { + logger.error("Failed to rollback transaction: {}", rollbackEx.getMessage(), rollbackEx); + } + } + throw e; + } catch (RuntimeException e) { + // Rollback on any RuntimeException and wrap in DocumentPersistenceException if (connection != null) { try { connection.rollback(); @@ -59,9 +70,16 @@ public class SqliteUnitOfWorkAdapter implements UnitOfWorkPort { logger.error("Failed to rollback transaction: {}", rollbackEx.getMessage(), rollbackEx); } } - // Re-throw as DocumentPersistenceException if not already - if (e instanceof DocumentPersistenceException) { - throw (DocumentPersistenceException) e; + throw new DocumentPersistenceException("Transaction failed: " + e.getMessage(), e); + } catch (SQLException e) { + // Rollback for any SQL error + if (connection != null) { + try { + connection.rollback(); + logger.debug("Transaction rolled back due to error: {}", e.getMessage()); + } catch (SQLException rollbackEx) { + logger.error("Failed to rollback transaction: {}", rollbackEx.getMessage(), rollbackEx); + } } throw new DocumentPersistenceException("Transaction failed: " + e.getMessage(), e); } finally { @@ -84,53 +102,47 @@ public class SqliteUnitOfWorkAdapter implements UnitOfWorkPort { @Override public void saveProcessingAttempt(ProcessingAttempt attempt) { - try { - // Reuse the existing repository logic but with shared connection - SqliteProcessingAttemptRepositoryAdapter repo = - new SqliteProcessingAttemptRepositoryAdapter(jdbcUrl) { - @Override - protected Connection getConnection() throws SQLException { - return connection; - } - }; - repo.save(attempt); - } catch (Exception e) { - throw new DocumentPersistenceException("Failed to save processing attempt: " + e.getMessage(), e); - } + // Repository methods declare DocumentPersistenceException as the only thrown exception. + // Any other exception (NullPointerException, etc.) will propagate to the outer try-catch + // and be caught there. + SqliteProcessingAttemptRepositoryAdapter repo = + new SqliteProcessingAttemptRepositoryAdapter(jdbcUrl) { + @Override + protected Connection getConnection() throws SQLException { + return connection; + } + }; + repo.save(attempt); } @Override public void createDocumentRecord(DocumentRecord record) { - try { - // Reuse the existing repository logic but with shared connection - SqliteDocumentRecordRepositoryAdapter repo = - new SqliteDocumentRecordRepositoryAdapter(jdbcUrl) { - @Override - protected Connection getConnection() throws SQLException { - return connection; - } - }; - repo.create(record); - } catch (Exception e) { - throw new DocumentPersistenceException("Failed to create document record: " + e.getMessage(), e); - } + // Repository methods declare DocumentPersistenceException as the only thrown exception. + // Any other exception (NullPointerException, etc.) will propagate to the outer try-catch + // and be caught there. + SqliteDocumentRecordRepositoryAdapter repo = + new SqliteDocumentRecordRepositoryAdapter(jdbcUrl) { + @Override + protected Connection getConnection() throws SQLException { + return connection; + } + }; + repo.create(record); } @Override public void updateDocumentRecord(DocumentRecord record) { - try { - // Reuse the existing repository logic but with shared connection - SqliteDocumentRecordRepositoryAdapter repo = - new SqliteDocumentRecordRepositoryAdapter(jdbcUrl) { - @Override - protected Connection getConnection() throws SQLException { - return connection; - } - }; - repo.update(record); - } catch (Exception e) { - throw new DocumentPersistenceException("Failed to update document record: " + e.getMessage(), e); - } + // Repository methods declare DocumentPersistenceException as the only thrown exception. + // Any other exception (NullPointerException, etc.) will propagate to the outer try-catch + // and be caught there. + SqliteDocumentRecordRepositoryAdapter repo = + new SqliteDocumentRecordRepositoryAdapter(jdbcUrl) { + @Override + protected Connection getConnection() throws SQLException { + return connection; + } + }; + repo.update(record); } } } \ No newline at end of file diff --git a/pdf-umbenenner-application/src/main/java/de/gecheckt/pdf/umbenenner/application/usecase/DefaultBatchRunProcessingUseCase.java b/pdf-umbenenner-application/src/main/java/de/gecheckt/pdf/umbenenner/application/usecase/DefaultBatchRunProcessingUseCase.java index 724c293..daa7a7e 100644 --- a/pdf-umbenenner-application/src/main/java/de/gecheckt/pdf/umbenenner/application/usecase/DefaultBatchRunProcessingUseCase.java +++ b/pdf-umbenenner-application/src/main/java/de/gecheckt/pdf/umbenenner/application/usecase/DefaultBatchRunProcessingUseCase.java @@ -211,7 +211,7 @@ public class DefaultBatchRunProcessingUseCase implements BatchRunProcessingUseCa try { runLockPort.release(); logger.debug("Run lock released."); - } catch (Exception e) { + } catch (RuntimeException e) { logger.warn("Warning: Failed to release run lock.", e); } }