Nachbearbeitung: Meilensteinbezüge aus Produktiv-JavaDoc und
package-info entfernt
This commit is contained in:
@@ -12,15 +12,11 @@ import de.gecheckt.pdf.umbenenner.domain.model.BatchRunContext;
|
||||
* interface. It receives the batch run outcome and makes it available to the Bootstrap layer
|
||||
* for exit code determination and logging.
|
||||
* <p>
|
||||
* AP-003 Implementation: Minimal no-op command to validate the call chain from CLI to Application.
|
||||
* <p>
|
||||
* M2-AP-002 Update: Returns {@link BatchRunOutcome} instead of boolean,
|
||||
* allowing Bootstrap to systematically derive exit codes (AP-007).
|
||||
* <p>
|
||||
* M2-AP-003 Update: Accepts {@link BatchRunContext} and passes it to the use case,
|
||||
* Returns {@link BatchRunOutcome} to allow Bootstrap to systematically derive exit codes.
|
||||
* Accepts {@link BatchRunContext} and passes it to the use case,
|
||||
* enabling run ID and timing tracking throughout the batch cycle.
|
||||
* <p>
|
||||
* M2-AP-005 Update: Dependency inversion achieved - this adapter depends only on the
|
||||
* Dependency inversion achieved - this adapter depends only on the
|
||||
* BatchRunProcessingUseCase interface, not on any concrete implementation. Bootstrap
|
||||
* is responsible for injecting the appropriate use case implementation.
|
||||
*/
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
* Components:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.adapter.in.cli.SchedulerBatchCommand}
|
||||
* — CLI entry point that delegates to BatchRunProcessingUseCase interface (AP-005)</li>
|
||||
* — CLI entry point that delegates to BatchRunProcessingUseCase interface</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* M2-AP-005 Architecture:
|
||||
* Adapter Architecture:
|
||||
* <ul>
|
||||
* <li>Adapter depends on: {@link de.gecheckt.pdf.umbenenner.application.port.in.BatchRunProcessingUseCase} (interface)</li>
|
||||
* <li>Adapter does not depend on: any concrete use case implementation</li>
|
||||
|
||||
@@ -34,8 +34,6 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentLocator;
|
||||
* <strong>Technical failure handling:</strong> Any I/O errors, path resolution issues,
|
||||
* or cryptographic problems are converted to {@link FingerprintTechnicalError} results
|
||||
* without throwing exceptions. Pre-fingerprint failures are not historized in SQLite.
|
||||
*
|
||||
* @since M4-AP-002
|
||||
*/
|
||||
public class Sha256FingerprintAdapter implements FingerprintPort {
|
||||
|
||||
|
||||
@@ -7,6 +7,5 @@
|
||||
* <p>All file I/O and cryptographic operations are strictly confined to this adapter layer,
|
||||
* maintaining the hexagonal architecture boundary.
|
||||
*
|
||||
* @since M4-AP-002
|
||||
*/
|
||||
package de.gecheckt.pdf.umbenenner.adapter.out.fingerprint;
|
||||
@@ -4,10 +4,10 @@
|
||||
* Components:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.adapter.out.lock.FilesystemRunLockPortAdapter}
|
||||
* — File-based run lock that prevents concurrent instances (AP-006)</li>
|
||||
* — File-based run lock that prevents concurrent instances</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* AP-006: Uses atomic file creation ({@code CREATE_NEW}) to establish an exclusive lock.
|
||||
* Implementation details: Uses atomic file creation ({@code CREATE_NEW}) to establish an exclusive lock.
|
||||
* Stores the acquiring process PID in the lock file for diagnostics.
|
||||
* Release is best-effort and logs a warning on failure without throwing.
|
||||
*/
|
||||
|
||||
@@ -19,7 +19,7 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate;
|
||||
/**
|
||||
* PDFBox-based implementation of {@link PdfTextExtractionPort}.
|
||||
* <p>
|
||||
* AP-003 Implementation: Extracts text content and page count from a single PDF document
|
||||
* Extracts text content and page count from a single PDF document
|
||||
* using Apache PDFBox. All technical problems during extraction are reported as
|
||||
* {@link de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionTechnicalError}.
|
||||
* <p>
|
||||
@@ -29,7 +29,7 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate;
|
||||
* <li>Extracts complete text from all pages (may be empty)</li>
|
||||
* <li>Counts total page count</li>
|
||||
* <li>Returns results as typed {@link PdfExtractionResult} (no exceptions thrown)</li>
|
||||
* <li>All extraction failures are treated as technical errors (AP-003 scope)</li>
|
||||
* <li>All extraction failures are treated as technical errors</li>
|
||||
* <li>PDFBox is encapsulated and never exposed beyond this adapter</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
@@ -41,7 +41,7 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate;
|
||||
* <li>All three values are combined into {@link PdfExtractionSuccess}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Technical error cases (AP-003):
|
||||
* Technical error cases:
|
||||
* <ul>
|
||||
* <li>File not found or unreadable</li>
|
||||
* <li>PDF cannot be loaded by PDFBox (any load error)</li>
|
||||
@@ -49,14 +49,12 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate;
|
||||
* <li>Text extraction fails or throws exception</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Non-goals (handled in later APs):
|
||||
* Out of scope (handled elsewhere):
|
||||
* <ul>
|
||||
* <li>Fachliche Bewertung des extrahierten Texts (AP-004)</li>
|
||||
* <li>Page limit checking (AP-004)</li>
|
||||
* <li>Fachliche Bewertung des extrahierten Texts</li>
|
||||
* <li>Page limit checking</li>
|
||||
* <li>Text normalization or preprocessing</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since M3-AP-003
|
||||
*/
|
||||
public class PdfTextExtractionPortAdapter implements PdfTextExtractionPort {
|
||||
|
||||
@@ -68,8 +66,8 @@ public class PdfTextExtractionPortAdapter implements PdfTextExtractionPort {
|
||||
* <p>
|
||||
* The locator is expected to contain an absolute file path as a String (adapter-internal convention).
|
||||
* <p>
|
||||
* In M3-AP-003, all technical problems are reported as {@link PdfExtractionTechnicalError}.
|
||||
* Fachliche Bewertungen like "text is not usable" are deferred to AP-004.
|
||||
* All technical problems are reported as {@link PdfExtractionTechnicalError}.
|
||||
* Fachliche Bewertungen like "text is not usable" are handled elsewhere.
|
||||
*
|
||||
* @param candidate the document to extract; must be non-null
|
||||
* @return a {@link PdfExtractionResult} encoding the outcome:
|
||||
@@ -113,12 +111,12 @@ public class PdfTextExtractionPortAdapter implements PdfTextExtractionPort {
|
||||
}
|
||||
|
||||
// Extract text from all pages
|
||||
// Note: extractedText may be empty string, which is valid in M3 (no fachliche validation here)
|
||||
// Note: extractedText may be empty string, which is valid (no fachliche validation here)
|
||||
PDFTextStripper textStripper = new PDFTextStripper();
|
||||
String extractedText = textStripper.getText(document);
|
||||
|
||||
// Success: return extracted text and page count
|
||||
// (Empty text is not an error in AP-003; fachliche validation is AP-004)
|
||||
// (Empty text is not an error; fachliche validation is handled elsewhere)
|
||||
PdfPageCount pageCountTyped = new PdfPageCount(pageCount);
|
||||
return new PdfExtractionSuccess(extractedText, pageCountTyped);
|
||||
} finally {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* PDFBox-based adapter for PDF text extraction.
|
||||
* <p>
|
||||
* <strong>M3-AP-003:</strong> This package contains the sole implementation
|
||||
* This package contains the sole implementation
|
||||
* of {@link de.gecheckt.pdf.umbenenner.application.port.out.PdfTextExtractionPort},
|
||||
* using Apache PDFBox to extract text and page count from PDF documents.
|
||||
* <p>
|
||||
* <strong>Scope (AP-003):</strong>
|
||||
* <strong>Scope:</strong>
|
||||
* <ul>
|
||||
* <li>Pure technical extraction: read PDF, extract text, count pages</li>
|
||||
* <li>All extraction problems (file not found, PDF unreadable, PDFBox errors) → {@link de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionTechnicalError}</li>
|
||||
@@ -14,21 +14,18 @@
|
||||
* <li>Results always typed as {@link de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionResult}, never exceptions</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <strong>Restriction:</strong>
|
||||
* <strong>Result types used:</strong>
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionContentError} is reserved for later APs</li>
|
||||
* <li>AP-003 adapter uses only {@link de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionSuccess} and
|
||||
* {@link de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionTechnicalError}</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionSuccess} for successful text extraction</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.PdfExtractionTechnicalError} for technical problems</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <strong>Out of scope (handled in later APs):</strong>
|
||||
* <strong>Out of scope:</strong>
|
||||
* <ul>
|
||||
* <li>Text validation or quality assessment (AP-004)</li>
|
||||
* <li>Page limit checking (AP-004)</li>
|
||||
* <li>Text validation or quality assessment</li>
|
||||
* <li>Page limit checking</li>
|
||||
* <li>Text normalization or preprocessing</li>
|
||||
* <li>Fachliche Bewertung of extracted content</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since M3-AP-003
|
||||
*/
|
||||
package de.gecheckt.pdf.umbenenner.adapter.out.pdfextraction;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
/**
|
||||
* Source document adapters for discovering and accessing PDF candidates.
|
||||
* <p>
|
||||
* M3-AP-002 implementations:
|
||||
* Implementations:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.adapter.out.sourcedocument.SourceDocumentCandidatesPortAdapter}
|
||||
* — File-system based discovery of PDF candidates from the source folder</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since M3-AP-002
|
||||
*/
|
||||
package de.gecheckt.pdf.umbenenner.adapter.out.sourcedocument;
|
||||
|
||||
@@ -34,8 +34,6 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentLocator;
|
||||
* <strong>Architecture boundary:</strong> All JDBC and SQLite details are strictly
|
||||
* confined to this class. No JDBC types appear in the port interface or in any
|
||||
* application/domain type.
|
||||
*
|
||||
* @since M4-AP-004
|
||||
*/
|
||||
public class SqliteDocumentRecordRepositoryAdapter implements DocumentRecordRepository {
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint;
|
||||
* <strong>Architecture boundary:</strong> All JDBC and SQLite details are strictly
|
||||
* confined to this class. No JDBC types appear in the port interface or in any
|
||||
* application/domain type.
|
||||
*
|
||||
* @since M4-AP-005
|
||||
*/
|
||||
public class SqliteProcessingAttemptRepositoryAdapter implements ProcessingAttemptRepository {
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import de.gecheckt.pdf.umbenenner.application.port.out.PersistenceSchemaInitiali
|
||||
/**
|
||||
* SQLite implementation of {@link PersistenceSchemaInitializationPort}.
|
||||
* <p>
|
||||
* Creates or verifies the M4 two-level persistence schema in the configured SQLite
|
||||
* Creates or verifies the two-level persistence schema in the configured SQLite
|
||||
* database file. All DDL uses {@code IF NOT EXISTS} semantics, making the operation
|
||||
* fully idempotent: calling {@link #initializeSchema()} on an already-initialised
|
||||
* database succeeds without error and without modifying existing data.
|
||||
@@ -39,8 +39,6 @@ import de.gecheckt.pdf.umbenenner.application.port.out.PersistenceSchemaInitiali
|
||||
* <p>All JDBC connections, SQL DDL, and SQLite-specific behaviour are strictly confined
|
||||
* to this class. No JDBC or SQLite types appear in the port interface or in any
|
||||
* application/domain type.
|
||||
*
|
||||
* @since M4-AP-003
|
||||
*/
|
||||
public class SqliteSchemaInitializationAdapter implements PersistenceSchemaInitializationPort {
|
||||
|
||||
@@ -49,7 +47,7 @@ public class SqliteSchemaInitializationAdapter implements PersistenceSchemaIniti
|
||||
/**
|
||||
* DDL for the document master record table.
|
||||
* <p>
|
||||
* <strong>Columns (M4 mandatory fields):</strong>
|
||||
* <strong>Columns (mandatory fields):</strong>
|
||||
* <ul>
|
||||
* <li>{@code id} — internal surrogate primary key (auto-increment).</li>
|
||||
* <li>{@code fingerprint} — SHA-256 hex string; unique natural key; never null.</li>
|
||||
@@ -95,7 +93,7 @@ public class SqliteSchemaInitializationAdapter implements PersistenceSchemaIniti
|
||||
/**
|
||||
* DDL for the processing attempt history table.
|
||||
* <p>
|
||||
* <strong>Columns (M4 mandatory fields):</strong>
|
||||
* <strong>Columns (mandatory fields):</strong>
|
||||
* <ul>
|
||||
* <li>{@code id} — internal surrogate primary key (auto-increment).</li>
|
||||
* <li>{@code fingerprint} — foreign key reference to
|
||||
@@ -179,7 +177,7 @@ public class SqliteSchemaInitializationAdapter implements PersistenceSchemaIniti
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or verifies the M4 persistence schema in the SQLite database.
|
||||
* Creates or verifies the persistence schema in the SQLite database.
|
||||
* <p>
|
||||
* Executes the following DDL statements in order:
|
||||
* <ol>
|
||||
@@ -202,7 +200,7 @@ public class SqliteSchemaInitializationAdapter implements PersistenceSchemaIniti
|
||||
*/
|
||||
@Override
|
||||
public void initializeSchema() {
|
||||
logger.info("Initialising M4 SQLite schema at: {}", jdbcUrl);
|
||||
logger.info("Initialising SQLite persistence schema at: {}", jdbcUrl);
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl);
|
||||
Statement statement = connection.createStatement()) {
|
||||
|
||||
@@ -226,7 +224,7 @@ public class SqliteSchemaInitializationAdapter implements PersistenceSchemaIniti
|
||||
logger.info("M4 SQLite schema initialisation completed successfully.");
|
||||
|
||||
} catch (SQLException e) {
|
||||
String message = "Failed to initialise M4 SQLite schema at '" + jdbcUrl + "': " + e.getMessage();
|
||||
String message = "Failed to initialise SQLite persistence schema at '" + jdbcUrl + "': " + e.getMessage();
|
||||
logger.error(message, e);
|
||||
throw new DocumentPersistenceException(message, e);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ import de.gecheckt.pdf.umbenenner.application.port.out.UnitOfWorkPort;
|
||||
* <p>
|
||||
* Provides transactional semantics for coordinated writes to both the document record
|
||||
* and processing attempt repositories.
|
||||
*
|
||||
* @since M4-AP-006-fix
|
||||
*/
|
||||
public class SqliteUnitOfWorkAdapter implements UnitOfWorkPort {
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/**
|
||||
* SQLite persistence adapter for the M4 two-level persistence model.
|
||||
* SQLite persistence adapter for the two-level persistence model.
|
||||
*
|
||||
* <h2>Purpose</h2>
|
||||
* <p>This package contains the technical SQLite infrastructure for the M4 persistence
|
||||
* <p>This package contains the technical SQLite infrastructure for the persistence
|
||||
* layer. It is the only place in the entire application where JDBC connections, SQL DDL,
|
||||
* and SQLite-specific types are used. No JDBC or SQLite types leak into the
|
||||
* {@code application} or {@code domain} modules.
|
||||
*
|
||||
* <h2>Two-level persistence model</h2>
|
||||
* <p>M4 persistence is structured in exactly two levels:
|
||||
* <p>Persistence is structured in exactly two levels:
|
||||
* <ol>
|
||||
* <li><strong>Document master record</strong> ({@code document_record} table) —
|
||||
* one row per unique SHA-256 fingerprint; carries the current overall status,
|
||||
@@ -31,7 +31,5 @@
|
||||
* confined to this package. The application layer interacts exclusively through the
|
||||
* port interfaces defined in
|
||||
* {@code de.gecheckt.pdf.umbenenner.application.port.out}.
|
||||
*
|
||||
* @since M4-AP-003
|
||||
*/
|
||||
package de.gecheckt.pdf.umbenenner.adapter.out.sqlite;
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Typed immutable configuration model for PDF Umbenenner startup parameters.
|
||||
* AP-005: Represents all M1-relevant configuration properties with strong typing.
|
||||
*/
|
||||
public record StartConfiguration(
|
||||
Path sourceFolder,
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.util.List;
|
||||
* and basic path existence checks. Throws {@link InvalidStartConfigurationException}
|
||||
* if any validation rule fails.
|
||||
* <p>
|
||||
* M3/AP-007: Supports injected source folder validation for testability
|
||||
* Supports injected source folder validation for testability
|
||||
* (allows mocking of platform-dependent filesystem checks).
|
||||
*/
|
||||
public class StartConfigurationValidator {
|
||||
@@ -246,7 +246,7 @@ public class StartConfigurationValidator {
|
||||
* <p>
|
||||
* Uses {@code java.nio.file.Files} static methods to check existence, type, and readability.
|
||||
* <p>
|
||||
* M3/AP-007: This separation allows unit tests to inject alternative implementations
|
||||
* This separation allows unit tests to inject alternative implementations
|
||||
* that control the outcome of readability checks without relying on actual filesystem
|
||||
* permissions (which are platform-dependent).
|
||||
*/
|
||||
|
||||
@@ -10,15 +10,13 @@ package de.gecheckt.pdf.umbenenner.application.port.in;
|
||||
* The outcome is independent of individual document processing results;
|
||||
* it represents the batch operation itself (lock acquired, no critical startup failure, etc.).
|
||||
* <p>
|
||||
* Design Note: This contract is defined in AP-002 to enable AP-007 (exit code handling)
|
||||
* to derive exit codes systematically without requiring additional knowledge about
|
||||
* the batch run. Each outcome maps cleanly to an exit code semantic.
|
||||
* Design Note: This contract enables exit code handling to derive exit codes systematically
|
||||
* without requiring additional knowledge about the batch run. Each outcome maps cleanly
|
||||
* to an exit code semantic.
|
||||
* <p>
|
||||
* AP-007: Three distinct outcomes are now defined to make the difference between a
|
||||
* technically successful run, a controlled early termination due to start protection,
|
||||
* and a hard bootstrap failure explicit in both code and logs.
|
||||
*
|
||||
* @since M2-AP-002
|
||||
* Three distinct outcomes are defined to make the difference between a technically successful run,
|
||||
* a controlled early termination due to start protection, and a hard bootstrap failure
|
||||
* explicit in both code and logs.
|
||||
*/
|
||||
public enum BatchRunOutcome {
|
||||
|
||||
@@ -42,7 +40,6 @@ public enum BatchRunOutcome {
|
||||
* <p>
|
||||
* Maps to exit code 1.
|
||||
*
|
||||
* @since M2-AP-007
|
||||
*/
|
||||
LOCK_UNAVAILABLE("Another instance is already running; this run terminates immediately"),
|
||||
|
||||
@@ -98,7 +95,6 @@ public enum BatchRunOutcome {
|
||||
* the run lock being held by another instance.
|
||||
*
|
||||
* @return true if outcome is {@link #LOCK_UNAVAILABLE}, false otherwise
|
||||
* @since M2-AP-007
|
||||
*/
|
||||
public boolean isLockUnavailable() {
|
||||
return this == LOCK_UNAVAILABLE;
|
||||
|
||||
@@ -17,18 +17,13 @@ import de.gecheckt.pdf.umbenenner.domain.model.BatchRunContext;
|
||||
* <p>
|
||||
* The returned outcome is designed to be independent of individual document results,
|
||||
* representing only the batch operation itself. Individual document successes/failures
|
||||
* are tracked separately in persistence (future milestones).
|
||||
* are tracked separately in persistence.
|
||||
* <p>
|
||||
* M2-AP-002 Implementation:
|
||||
* Implementation details:
|
||||
* <ul>
|
||||
* <li>Port is defined with a structured return contract ({@link BatchRunOutcome})</li>
|
||||
* <li>Return model allows Bootstrap/CLI to systematically derive exit codes (AP-007)</li>
|
||||
* <li>No implementation of the use case itself yet (that is AP-004)</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* M2-AP-003 Update:
|
||||
* <ul>
|
||||
* <li>execute() now accepts a {@link BatchRunContext} containing the run ID and timing</li>
|
||||
* <li>Return model allows Bootstrap/CLI to systematically derive exit codes</li>
|
||||
* <li>execute() accepts a {@link BatchRunContext} containing the run ID and timing</li>
|
||||
* <li>The context flows through the entire batch cycle for correlation and logging</li>
|
||||
* </ul>
|
||||
*/
|
||||
|
||||
@@ -13,13 +13,11 @@
|
||||
* Return models:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.port.in.BatchRunOutcome}
|
||||
* — Structured result of a batch run, designed for exit code mapping (AP-007)</li>
|
||||
* — Structured result of a batch run, designed for exit code mapping</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Architecture Rule: Inbound ports are independent of implementation and contain no business logic.
|
||||
* They define "what can be done to the application". All dependencies point inward;
|
||||
* adapters depend on ports, not vice versa.
|
||||
*
|
||||
* @since M2-AP-002
|
||||
*/
|
||||
package de.gecheckt.pdf.umbenenner.application.port.in;
|
||||
|
||||
@@ -18,7 +18,6 @@ import java.time.Instant;
|
||||
* This port is defined in M2 for use in later milestones where timestamps
|
||||
* become relevant (e.g., run history, document date fallback).
|
||||
*
|
||||
* @since M2-AP-002
|
||||
*/
|
||||
public interface ClockPort {
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import java.util.Objects;
|
||||
* without an additional lookup.
|
||||
*
|
||||
* @param record the current master record for this document; never null
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public record DocumentKnownProcessable(DocumentRecord record) implements DocumentRecordLookupResult {
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
* {@link DocumentRecordLookupResult} hierarchy to allow exhaustive pattern matching
|
||||
* at the call site.
|
||||
*
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public class DocumentPersistenceException extends RuntimeException {
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ import java.util.Objects;
|
||||
* @param lastSuccessInstant timestamp of the successful processing, or {@code null}
|
||||
* @param createdAt timestamp when this record was first created; never null
|
||||
* @param updatedAt timestamp of the most recent update; never null
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public record DocumentRecord(
|
||||
DocumentFingerprint fingerprint,
|
||||
|
||||
@@ -21,7 +21,6 @@ package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
* <strong>Architecture boundary:</strong> No JDBC, SQLite, or filesystem types appear
|
||||
* in this sealed hierarchy or in any of its implementations.
|
||||
*
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public sealed interface DocumentRecordLookupResult
|
||||
permits DocumentUnknown,
|
||||
|
||||
@@ -29,7 +29,6 @@ import de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint;
|
||||
* in this interface or in any type it references. Mapping to and from the persistence
|
||||
* schema is the exclusive responsibility of the adapter implementation.
|
||||
*
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public interface DocumentRecordRepository {
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import java.util.Objects;
|
||||
* current record for the skip attempt historisation without an additional lookup.
|
||||
*
|
||||
* @param record the current (finally failed) master record for this document; never null
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public record DocumentTerminalFinalFailure(DocumentRecord record) implements DocumentRecordLookupResult {
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import java.util.Objects;
|
||||
* current record for the skip attempt historisation without an additional lookup.
|
||||
*
|
||||
* @param record the current (successful) master record for this document; never null
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public record DocumentTerminalSuccess(DocumentRecord record) implements DocumentRecordLookupResult {
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
* <p>
|
||||
* This variant carries no data because there is no existing record to return.
|
||||
*
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public record DocumentUnknown() implements DocumentRecordLookupResult {
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
* must be >= 0
|
||||
* @param transientErrorCount number of transient technical errors recorded so far;
|
||||
* must be >= 0
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public record FailureCounters(int contentErrorCount, int transientErrorCount) {
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate;
|
||||
* and the candidate cannot be identified; consequently no SQLite attempt record is
|
||||
* created for this candidate in M4.
|
||||
*
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public interface FingerprintPort {
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
* the document cannot be identified and <em>no</em> SQLite attempt record is created.
|
||||
* The failure is treated as a non-identifiable run event.
|
||||
*
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public sealed interface FingerprintResult permits FingerprintSuccess, FingerprintTechnicalError {
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import java.util.Objects;
|
||||
* for all subsequent persistence operations in M4.
|
||||
*
|
||||
* @param fingerprint the successfully computed fingerprint; never null
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public record FingerprintSuccess(DocumentFingerprint fingerprint) implements FingerprintResult {
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import java.util.Objects;
|
||||
*
|
||||
* @param errorMessage human-readable description of the failure; never null or blank
|
||||
* @param cause the underlying throwable, or {@code null} if not available
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public record FingerprintTechnicalError(String errorMessage, Throwable cause) implements FingerprintResult {
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ import de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate;
|
||||
* <li>Persistence or caching of results</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since M3-AP-001
|
||||
*/
|
||||
public interface PdfTextExtractionPort {
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import java.util.Objects;
|
||||
*
|
||||
* @param errorMessage human-readable description of the persistence failure; never null or blank
|
||||
* @param cause the underlying throwable, or {@code null} if not available
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public record PersistenceLookupTechnicalFailure(String errorMessage, Throwable cause)
|
||||
implements DocumentRecordLookupResult {
|
||||
|
||||
@@ -23,7 +23,6 @@ package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
* in this interface. All schema DDL and connection management are confined to the
|
||||
* {@code adapter-out} implementation.
|
||||
*
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public interface PersistenceSchemaInitializationPort {
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ import java.util.Objects;
|
||||
* @param failureClass failure classification, or {@code null} for non-failure statuses
|
||||
* @param failureMessage failure description, or {@code null} for non-failure statuses
|
||||
* @param retryable whether this failure should be retried in a later run
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public record ProcessingAttempt(
|
||||
DocumentFingerprint fingerprint,
|
||||
|
||||
@@ -26,7 +26,6 @@ import java.util.List;
|
||||
* in this interface. Mapping to and from the persistence schema is the exclusive
|
||||
* responsibility of the adapter implementation.
|
||||
*
|
||||
* @since M4-AP-001
|
||||
*/
|
||||
public interface ProcessingAttemptRepository {
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
* This port is used by the batch use case (M2-AP-004) but not implemented in M2;
|
||||
* implementation follows in M2-AP-006.
|
||||
*
|
||||
* @since M2-AP-002
|
||||
*/
|
||||
public interface RunLockPort {
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
* This is a controlled failure mode, not a programming error. Applications should
|
||||
* catch this exception and exit gracefully with the appropriate exit code.
|
||||
*
|
||||
* @since M2-AP-002
|
||||
*/
|
||||
public class RunLockUnavailableException extends RuntimeException {
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
* This is a runtime exception, allowing adapters to propagate filesystem errors
|
||||
* without forcing try/catch blocks in the application layer.
|
||||
*
|
||||
* @since M3-AP-001
|
||||
*/
|
||||
public final class SourceDocumentAccessException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.util.List;
|
||||
* <li>This enforces the hexagonal boundary and allows easy adapter swapping (e.g., cloud storage)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since M3-AP-001
|
||||
*/
|
||||
public interface SourceDocumentCandidatesPort {
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import java.util.function.Consumer;
|
||||
* Ensures that related persistence operations (such as saving a processing attempt
|
||||
* and updating a document record) are executed atomically.
|
||||
*
|
||||
* @since M4-AP-006-fix
|
||||
*/
|
||||
public interface UnitOfWorkPort {
|
||||
|
||||
|
||||
@@ -4,17 +4,17 @@
|
||||
* Outbound ports define the contracts for interacting with external systems and infrastructure.
|
||||
* All calls flow FROM the application OUT TO infrastructure adapters through these ports.
|
||||
* <p>
|
||||
* M2-AP-002 ports:
|
||||
* Configuration and runtime ports:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.port.out.ConfigurationPort}
|
||||
* — Loading application startup configuration (already M1)</li>
|
||||
* — Loading application startup configuration</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.port.out.RunLockPort}
|
||||
* — Exclusive run lock for preventing concurrent batch instances</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.port.out.ClockPort}
|
||||
* — System time access for timestamps and run context</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* M3-AP-001 ports:
|
||||
* Source document discovery and extraction ports:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.port.out.SourceDocumentCandidatesPort}
|
||||
* — Load PDF document candidates from the source folder</li>
|
||||
@@ -22,7 +22,7 @@
|
||||
* — Extract text content and page count from a single PDF</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* M4-AP-001 ports:
|
||||
* Persistence and fingerprinting ports:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.port.out.FingerprintPort}
|
||||
* — Compute the content-based SHA-256 fingerprint of a processing candidate</li>
|
||||
@@ -34,7 +34,7 @@
|
||||
* — Initialise the SQLite schema at program startup</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* M4-AP-001 value types and result types:
|
||||
* Value types and result types:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.port.out.FailureCounters}
|
||||
* — Immutable snapshot of content-error and transient-error counters per document</li>
|
||||
@@ -51,17 +51,15 @@
|
||||
* Exception types:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.port.out.RunLockUnavailableException}
|
||||
* — Thrown when run lock cannot be acquired (another instance running) (M2)</li>
|
||||
* — Thrown when run lock cannot be acquired (another instance running)</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.port.out.SourceDocumentAccessException}
|
||||
* — Thrown when source folder cannot be read or accessed (M3)</li>
|
||||
* — Thrown when source folder cannot be read or accessed</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.port.out.DocumentPersistenceException}
|
||||
* — Thrown when a persistence write operation or schema init fails (M4)</li>
|
||||
* — Thrown when a persistence write operation or schema init fails</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Architecture Rule: Outbound ports are implementation-agnostic and contain no business logic.
|
||||
* They define "what the application depends on externally". All dependencies point inward;
|
||||
* the application depends on ports, adapters implement ports.
|
||||
*
|
||||
* @since M2-AP-002
|
||||
*/
|
||||
package de.gecheckt.pdf.umbenenner.application.port.out;
|
||||
|
||||
@@ -33,7 +33,6 @@ import java.util.Objects;
|
||||
* <p>
|
||||
* This service is the single authoritative place for the decision rules:
|
||||
* idempotency checks, status/counter mapping, and consistent two-level persistence.
|
||||
* It is intentionally tightly scoped to AP-006 and contains no further logic.
|
||||
*
|
||||
* <h2>Processing order per candidate</h2>
|
||||
* <ol>
|
||||
@@ -76,8 +75,6 @@ import java.util.Objects;
|
||||
* Failures that occur before a successful fingerprint is available are <em>not</em>
|
||||
* historised in SQLite. They are handled by the caller and logged as non-identifiable
|
||||
* run events.
|
||||
*
|
||||
* @since AP-006
|
||||
*/
|
||||
public class DocumentProcessingCoordinator {
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* Application-level services for business logic evaluation and M4 orchestration.
|
||||
* Application-level services for business logic evaluation and document processing orchestration.
|
||||
* <p>
|
||||
* This package contains stateless, pure-logic services that evaluate document content,
|
||||
* apply business rules, and orchestrate the M4 per-document processing flow.
|
||||
* apply business rules, and orchestrate the per-document processing flow.
|
||||
* Services in this package:
|
||||
* <ul>
|
||||
* <li>Do not manage state or resources</li>
|
||||
@@ -14,31 +14,31 @@
|
||||
* <h2>Current services</h2>
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.service.PreCheckEvaluator}
|
||||
* — Pre-check evaluation (M3)</li>
|
||||
* — Pre-check evaluation logic</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.service.DocumentProcessingService}
|
||||
* — Complete M3 document processing pipeline orchestration</li>
|
||||
* — Complete document processing pipeline orchestration</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.service.M4DocumentProcessor}
|
||||
* — M4 per-document idempotency, status/counter mapping and consistent
|
||||
* two-level persistence (AP-006)</li>
|
||||
* — Per-document idempotency, status/counter mapping and consistent
|
||||
* two-level persistence</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>M4 processing flow ({@code M4DocumentProcessor})</h2>
|
||||
* <h2>Document processing flow ({@code M4DocumentProcessor})</h2>
|
||||
* <p>
|
||||
* The {@link de.gecheckt.pdf.umbenenner.application.service.M4DocumentProcessor}
|
||||
* implements the verbindliche M4 processing order per candidate:
|
||||
* implements the required processing order per candidate:
|
||||
* <ol>
|
||||
* <li>Load the document master record by fingerprint.</li>
|
||||
* <li>If overall status is {@code SUCCESS} → persist a skip attempt with
|
||||
* {@code SKIPPED_ALREADY_PROCESSED}; do not change counters.</li>
|
||||
* <li>If overall status is {@code FAILED_FINAL} → persist a skip attempt with
|
||||
* {@code SKIPPED_FINAL_FAILURE}; do not change counters.</li>
|
||||
* <li>Otherwise map the M3 outcome into M4 status, counters and retryable flag
|
||||
* using the M4 minimal rules.</li>
|
||||
* <li>Otherwise map the extraction outcome into status, counters and retryable flag
|
||||
* using the minimal rules.</li>
|
||||
* <li>Persist exactly one historised processing attempt.</li>
|
||||
* <li>Persist the updated document master record.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <h2>M4 minimal rules (status and counter semantics)</h2>
|
||||
* <h2>Processing rules (status and counter semantics)</h2>
|
||||
* <ul>
|
||||
* <li>First deterministic content error → {@code FAILED_RETRYABLE},
|
||||
* content error counter +1, {@code retryable=true}.</li>
|
||||
@@ -54,7 +54,7 @@
|
||||
* For every identified document, the processing attempt and the master record are
|
||||
* written in sequence. If either write fails, the failure is caught and logged;
|
||||
* the batch run continues with the next candidate. True transactionality across
|
||||
* two separate repository calls is not available in the M4 scope; this is a known
|
||||
* two separate repository calls is not available due to the two-level persistence design; this is a known
|
||||
* and documented limitation.
|
||||
*
|
||||
* <h2>Pre-fingerprint failures</h2>
|
||||
|
||||
@@ -76,7 +76,6 @@ import java.util.Objects;
|
||||
* <li>No retry rules for KI or target copy failures.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since AP-004 (extended in AP-006)
|
||||
*/
|
||||
public class DefaultBatchRunProcessingUseCase implements BatchRunProcessingUseCase {
|
||||
|
||||
|
||||
@@ -4,25 +4,23 @@
|
||||
* Implementations:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.application.usecase.DefaultBatchRunProcessingUseCase}
|
||||
* — Production implementation with run lock, M4 fingerprint-based idempotency,
|
||||
* and consistent two-level persistence (extended in M4-AP-006)</li>
|
||||
* — Production implementation with run lock, fingerprint-based idempotency,
|
||||
* and consistent two-level persistence</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <h2>M4 processing order (AP-006)</h2>
|
||||
* <h2>Processing order per candidate</h2>
|
||||
* <p>
|
||||
* For each candidate, {@link de.gecheckt.pdf.umbenenner.application.usecase.DefaultBatchRunProcessingUseCase}
|
||||
* The {@link de.gecheckt.pdf.umbenenner.application.usecase.DefaultBatchRunProcessingUseCase}
|
||||
* enforces this order:
|
||||
* <ol>
|
||||
* <li>Compute SHA-256 fingerprint of the candidate file content.</li>
|
||||
* <li>If fingerprint computation fails: log as non-identifiable run event;
|
||||
* do NOT write any SQLite record; continue with next candidate.</li>
|
||||
* <li>Run the M3 pipeline (PDF extraction + pre-checks).</li>
|
||||
* <li>Run the document extraction and pre-checks pipeline.</li>
|
||||
* <li>Delegate to {@link de.gecheckt.pdf.umbenenner.application.service.M4DocumentProcessor}
|
||||
* for idempotency check, status/counter mapping, and consistent persistence.</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* All implementations are infrastructure-agnostic and interact only through ports.
|
||||
*
|
||||
* @since M2 (extended in M4-AP-006)
|
||||
*/
|
||||
package de.gecheckt.pdf.umbenenner.application.usecase;
|
||||
|
||||
@@ -42,7 +42,7 @@ import de.gecheckt.pdf.umbenenner.domain.model.RunId;
|
||||
* Responsibilities:
|
||||
* <ol>
|
||||
* <li>Load and validate the startup configuration.</li>
|
||||
* <li>Initialise the SQLite persistence schema (M4-AP-007).</li>
|
||||
* <li>Initialise the SQLite persistence schema.</li>
|
||||
* <li>Resolve the run-lock file path (with default fallback).</li>
|
||||
* <li>Create and wire all ports and adapters via configured factories.</li>
|
||||
* <li>Start the CLI adapter and execute the batch use case.</li>
|
||||
@@ -59,22 +59,20 @@ import de.gecheckt.pdf.umbenenner.domain.model.RunId;
|
||||
* during the run.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>M4 wiring (AP-006 / AP-007)</h2>
|
||||
* <h2>Adapter wiring</h2>
|
||||
* <p>
|
||||
* The production constructor wires the following M4 adapters:
|
||||
* The production constructor wires the following adapters:
|
||||
* <ul>
|
||||
* <li>{@link SqliteSchemaInitializationAdapter} — SQLite schema DDL at startup (AP-007).</li>
|
||||
* <li>{@link SqliteSchemaInitializationAdapter} — SQLite schema DDL at startup.</li>
|
||||
* <li>{@link Sha256FingerprintAdapter} — SHA-256 content fingerprinting.</li>
|
||||
* <li>{@link SqliteDocumentRecordRepositoryAdapter} — document master record CRUD.</li>
|
||||
* <li>{@link SqliteProcessingAttemptRepositoryAdapter} — attempt history CRUD.</li>
|
||||
* <li>{@link SqliteUnitOfWorkAdapter} — atomic persistence operations.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Schema initialisation is performed once in {@link #run()} before the batch loop starts
|
||||
* (AP-007). A {@link DocumentPersistenceException} during schema initialisation is treated
|
||||
* Schema initialisation is performed once in {@link #run()} before the batch loop starts.
|
||||
* A {@link DocumentPersistenceException} during schema initialisation is treated
|
||||
* as a hard startup failure and results in exit code 1.
|
||||
*
|
||||
* @since M2 (extended in M4-AP-006, M4-AP-007)
|
||||
*/
|
||||
public class BootstrapRunner {
|
||||
|
||||
@@ -142,21 +140,21 @@ public class BootstrapRunner {
|
||||
/**
|
||||
* Creates the BootstrapRunner with default factories for production use.
|
||||
* <p>
|
||||
* Wires the M4 processing pipeline:
|
||||
* Wires the processing pipeline with the following adapters:
|
||||
* <ul>
|
||||
* <li>{@link PropertiesConfigurationPortAdapter} for configuration loading.</li>
|
||||
* <li>{@link FilesystemRunLockPortAdapter} for exclusive run locking.</li>
|
||||
* <li>{@link SourceDocumentCandidatesPortAdapter} for PDF candidate discovery.</li>
|
||||
* <li>{@link PdfTextExtractionPortAdapter} for PDFBox-based text and page count extraction.</li>
|
||||
* <li>{@link Sha256FingerprintAdapter} for SHA-256 content fingerprinting.</li>
|
||||
* <li>{@link SqliteSchemaInitializationAdapter} for SQLite schema DDL at startup (AP-007).</li>
|
||||
* <li>{@link SqliteSchemaInitializationAdapter} for SQLite schema DDL at startup.</li>
|
||||
* <li>{@link SqliteDocumentRecordRepositoryAdapter} for document master record CRUD.</li>
|
||||
* <li>{@link SqliteProcessingAttemptRepositoryAdapter} for attempt history CRUD.</li>
|
||||
* <li>{@link SqliteUnitOfWorkAdapter} for atomic persistence operations.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Schema initialisation is performed explicitly in {@link #run()} before the batch loop
|
||||
* begins (AP-007). Failure during initialisation aborts the run with exit code 1.
|
||||
* begins. Failure during initialisation aborts the run with exit code 1.
|
||||
*/
|
||||
public BootstrapRunner() {
|
||||
this.configPortFactory = PropertiesConfigurationPortAdapter::new;
|
||||
@@ -191,7 +189,7 @@ public class BootstrapRunner {
|
||||
* @param configPortFactory factory for creating ConfigurationPort instances
|
||||
* @param runLockPortFactory factory for creating RunLockPort instances
|
||||
* @param validatorFactory factory for creating StartConfigurationValidator instances
|
||||
* @param schemaInitPortFactory factory for creating PersistenceSchemaInitializationPort instances (AP-007)
|
||||
* @param schemaInitPortFactory factory for creating PersistenceSchemaInitializationPort instances
|
||||
* @param useCaseFactory factory for creating BatchRunProcessingUseCase instances
|
||||
* @param commandFactory factory for creating SchedulerBatchCommand instances
|
||||
*/
|
||||
@@ -212,7 +210,7 @@ public class BootstrapRunner {
|
||||
/**
|
||||
* Runs the application startup sequence.
|
||||
* <p>
|
||||
* M4 startup flow (AP-007):
|
||||
* Startup flow:
|
||||
* <ol>
|
||||
* <li>Load configuration via {@link ConfigurationPort}.</li>
|
||||
* <li>Validate the configuration via {@link StartConfigurationValidator}; validation
|
||||
@@ -223,7 +221,7 @@ public class BootstrapRunner {
|
||||
* batch document loop begins. A {@link DocumentPersistenceException} here is a hard
|
||||
* startup failure and causes exit code 1.</li>
|
||||
* <li>Resolve the run-lock file path, apply default if not configured.</li>
|
||||
* <li>Create the batch use case with all M4 adapters wired.</li>
|
||||
* <li>Create the batch use case with all required adapters wired.</li>
|
||||
* <li>Execute the CLI command and map the outcome to an exit code.</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
|
||||
@@ -6,8 +6,8 @@ import org.apache.logging.log4j.Logger;
|
||||
/**
|
||||
* Main entry point for the PDF Umbenenner application.
|
||||
* <p>
|
||||
* AP-003: Delegates to {@link BootstrapRunner} for manual object graph construction
|
||||
* and execution of the minimal no-op startup path.
|
||||
* Delegates to {@link BootstrapRunner} for manual object graph construction
|
||||
* and execution of the startup sequence.
|
||||
*/
|
||||
public class PdfUmbenennerApplication {
|
||||
|
||||
|
||||
@@ -7,28 +7,28 @@
|
||||
* Components:
|
||||
* <ul>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.bootstrap.BootstrapRunner}
|
||||
* — Orchestrator of startup sequence and object graph construction (M2-AP-005)</li>
|
||||
* — Orchestrator of startup sequence and object graph construction</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.bootstrap.PdfUmbenennerApplication}
|
||||
* — Main entry point that invokes BootstrapRunner (M1)</li>
|
||||
* — Main entry point that invokes BootstrapRunner</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* M2 Implementation:
|
||||
* Implementation approach:
|
||||
* <ul>
|
||||
* <li>Uses factory pattern with pluggable interfaces for all ports and use cases</li>
|
||||
* <li>Manually constructs object graph without framework dependencies</li>
|
||||
* <li>Ensures strict inward dependency direction toward application and domain</li>
|
||||
* <li>Ready for extension by later milestones via factory methods</li>
|
||||
* <li>Provides a minimal, controlled startup path without dependency injection frameworks</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* AP-003: Provides a minimal, controlled startup path without dependency injection frameworks.
|
||||
* <p>
|
||||
* AP-005: CLI adapter and complete M2 object graph wiring.
|
||||
* <p>
|
||||
* AP-006: Wires FilesystemRunLockPortAdapter (adapter-out) from validated config; retired temporary no-op lock.
|
||||
* <p>
|
||||
* AP-007: Adds SQLite persistence schema initialization at startup via
|
||||
* Startup sequence:
|
||||
* <ul>
|
||||
* <li>Load and validate configuration from properties file and environment variables</li>
|
||||
* <li>Wire run lock adapter to prevent concurrent instances</li>
|
||||
* <li>Initialize SQLite persistence schema at startup via
|
||||
* {@link de.gecheckt.pdf.umbenenner.application.port.out.PersistenceSchemaInitializationPort},
|
||||
* ensuring the database is ready before document processing begins. Schema initialization failure
|
||||
* is treated as a hard bootstrap error and causes exit code 1.
|
||||
* ensuring the database is ready before document processing begins.</li>
|
||||
* <li>Schema initialization failure is treated as a hard bootstrap error and causes exit code 1</li>
|
||||
* <li>Invoke the batch processing CLI adapter</li>
|
||||
* </ul>
|
||||
*/
|
||||
package de.gecheckt.pdf.umbenenner.bootstrap;
|
||||
@@ -7,7 +7,7 @@ package de.gecheckt.pdf.umbenenner.domain.model;
|
||||
* master record ({@code DocumentRecord}) or in a single attempt record
|
||||
* ({@code ProcessingAttempt}).
|
||||
* <p>
|
||||
* <strong>Overall-status semantics (master record, M4):</strong>
|
||||
* <strong>Overall-status semantics (master record):</strong>
|
||||
* <ul>
|
||||
* <li>{@link #SUCCESS} — document was fully processed; skip in all future runs.</li>
|
||||
* <li>{@link #FAILED_RETRYABLE} — last attempt failed but is retryable; process again
|
||||
@@ -17,7 +17,7 @@ package de.gecheckt.pdf.umbenenner.domain.model;
|
||||
* run); if found persisted after a crash, treat as {@link #FAILED_RETRYABLE}.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <strong>Attempt-status semantics (attempt history, M4):</strong>
|
||||
* <strong>Attempt-status semantics (attempt history):</strong>
|
||||
* <ul>
|
||||
* <li>{@link #SUCCESS} — this attempt completed successfully.</li>
|
||||
* <li>{@link #FAILED_RETRYABLE} — this attempt failed; a future attempt is allowed.</li>
|
||||
@@ -28,7 +28,7 @@ package de.gecheckt.pdf.umbenenner.domain.model;
|
||||
* overall status was already {@link #FAILED_FINAL}.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <strong>M4 counter rules:</strong>
|
||||
* <strong>Counter rules:</strong>
|
||||
* <ul>
|
||||
* <li>Only {@link #FAILED_RETRYABLE} and {@link #FAILED_FINAL} outcomes may increase
|
||||
* a failure counter (content-error or transient-error counter).</li>
|
||||
@@ -41,7 +41,6 @@ package de.gecheckt.pdf.umbenenner.domain.model;
|
||||
* transient-error counter +1.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since M2-AP-001
|
||||
*/
|
||||
public enum ProcessingStatus {
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.ProcessingStatus} — enumeration of all valid document processing states</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.RunId} — unique identifier for a batch run</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.BatchRunContext} — technical context for a batch run</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint} — content-based document identity (SHA-256 hex); primary key for M4 persistence (M4)</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.DocumentFingerprint} — content-based document identity (SHA-256 hex); primary key for persistence</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentCandidate} — discovered PDF from source folder</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.SourceDocumentLocator} — opaque locator passed from scan adapter to extraction adapter</li>
|
||||
* <li>{@link de.gecheckt.pdf.umbenenner.domain.model.PdfPageCount} — typed page count validation</li>
|
||||
|
||||
Reference in New Issue
Block a user