1
0

M4 AP-006 AP-007-Scope im Bootstrap trennen

This commit is contained in:
2026-04-03 10:56:22 +02:00
parent 30f070f2a6
commit 049aa361db

View File

@@ -16,7 +16,6 @@ import de.gecheckt.pdf.umbenenner.adapter.out.pdfextraction.PdfTextExtractionPor
import de.gecheckt.pdf.umbenenner.adapter.out.sourcedocument.SourceDocumentCandidatesPortAdapter; import de.gecheckt.pdf.umbenenner.adapter.out.sourcedocument.SourceDocumentCandidatesPortAdapter;
import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteDocumentRecordRepositoryAdapter; import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteDocumentRecordRepositoryAdapter;
import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteProcessingAttemptRepositoryAdapter; import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteProcessingAttemptRepositoryAdapter;
import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteSchemaInitializationAdapter;
import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteUnitOfWorkAdapter; import de.gecheckt.pdf.umbenenner.adapter.out.sqlite.SqliteUnitOfWorkAdapter;
import de.gecheckt.pdf.umbenenner.application.config.InvalidStartConfigurationException; import de.gecheckt.pdf.umbenenner.application.config.InvalidStartConfigurationException;
import de.gecheckt.pdf.umbenenner.application.config.StartConfiguration; import de.gecheckt.pdf.umbenenner.application.config.StartConfiguration;
@@ -27,7 +26,6 @@ import de.gecheckt.pdf.umbenenner.application.port.out.ConfigurationPort;
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentPersistenceException; import de.gecheckt.pdf.umbenenner.application.port.out.DocumentPersistenceException;
import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecordRepository; import de.gecheckt.pdf.umbenenner.application.port.out.DocumentRecordRepository;
import de.gecheckt.pdf.umbenenner.application.port.out.FingerprintPort; import de.gecheckt.pdf.umbenenner.application.port.out.FingerprintPort;
import de.gecheckt.pdf.umbenenner.application.port.out.PersistenceSchemaInitializationPort;
import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingAttemptRepository; import de.gecheckt.pdf.umbenenner.application.port.out.ProcessingAttemptRepository;
import de.gecheckt.pdf.umbenenner.application.port.out.RunLockPort; import de.gecheckt.pdf.umbenenner.application.port.out.RunLockPort;
import de.gecheckt.pdf.umbenenner.application.port.out.UnitOfWorkPort; import de.gecheckt.pdf.umbenenner.application.port.out.UnitOfWorkPort;
@@ -58,16 +56,17 @@ import de.gecheckt.pdf.umbenenner.domain.model.RunId;
* during the run.</li> * during the run.</li>
* </ul> * </ul>
* *
* <h2>M4 wiring</h2> * <h2>M4 wiring (AP-006)</h2>
* <p> * <p>
* The production constructor wires the following M4 adapters via the UseCaseFactory: * The production constructor wires the following M4 adapters via the UseCaseFactory:
* <ul> * <ul>
* <li>{@link Sha256FingerprintAdapter} — SHA-256 content fingerprinting.</li> * <li>{@link Sha256FingerprintAdapter} — SHA-256 content fingerprinting.</li>
* <li>{@link SqliteSchemaInitializationAdapter} — schema initialisation (AP-007).</li>
* <li>{@link SqliteDocumentRecordRepositoryAdapter} — document master record CRUD.</li> * <li>{@link SqliteDocumentRecordRepositoryAdapter} — document master record CRUD.</li>
* <li>{@link SqliteProcessingAttemptRepositoryAdapter} — attempt history CRUD.</li> * <li>{@link SqliteProcessingAttemptRepositoryAdapter} — attempt history CRUD.</li>
* <li>{@link SqliteUnitOfWorkAdapter} — atomic persistence operations.</li> * <li>{@link SqliteUnitOfWorkAdapter} — atomic persistence operations.</li>
* </ul> * </ul>
* <p>
* Schema initialisation is AP-007 responsibility, not performed in AP-006.
* *
* @since M2 (extended in M4-AP-006) * @since M2 (extended in M4-AP-006)
*/ */
@@ -128,7 +127,7 @@ public class BootstrapRunner {
/** /**
* Creates the BootstrapRunner with default factories for production use. * Creates the BootstrapRunner with default factories for production use.
* <p> * <p>
* Wires the full M4 processing pipeline: * Wires the M4 processing pipeline:
* <ul> * <ul>
* <li>{@link PropertiesConfigurationPortAdapter} for configuration loading.</li> * <li>{@link PropertiesConfigurationPortAdapter} for configuration loading.</li>
* <li>{@link FilesystemRunLockPortAdapter} for exclusive run locking.</li> * <li>{@link FilesystemRunLockPortAdapter} for exclusive run locking.</li>
@@ -140,8 +139,7 @@ public class BootstrapRunner {
* <li>{@link SqliteUnitOfWorkAdapter} for atomic persistence operations.</li> * <li>{@link SqliteUnitOfWorkAdapter} for atomic persistence operations.</li>
* </ul> * </ul>
* <p> * <p>
* Schema initialisation is performed by the UseCaseFactory when the use case is created, * Schema initialisation is AP-007 responsibility and is NOT performed here.
* using {@link SqliteSchemaInitializationAdapter}. (AP-007 responsibility)
*/ */
public BootstrapRunner() { public BootstrapRunner() {
this.configPortFactory = PropertiesConfigurationPortAdapter::new; this.configPortFactory = PropertiesConfigurationPortAdapter::new;
@@ -149,11 +147,6 @@ public class BootstrapRunner {
this.validatorFactory = StartConfigurationValidator::new; this.validatorFactory = StartConfigurationValidator::new;
this.useCaseFactory = (config, lock) -> { this.useCaseFactory = (config, lock) -> {
String jdbcUrl = buildJdbcUrl(config); String jdbcUrl = buildJdbcUrl(config);
// AP-007: Initialize schema when the use case is created
if (config.sqliteFile() != null) {
PersistenceSchemaInitializationPort schemaPort = new SqliteSchemaInitializationAdapter(jdbcUrl);
schemaPort.initializeSchema();
}
FingerprintPort fingerprintPort = new Sha256FingerprintAdapter(); FingerprintPort fingerprintPort = new Sha256FingerprintAdapter();
DocumentRecordRepository documentRecordRepository = DocumentRecordRepository documentRecordRepository =
new SqliteDocumentRecordRepositoryAdapter(jdbcUrl); new SqliteDocumentRecordRepositoryAdapter(jdbcUrl);
@@ -201,8 +194,7 @@ public class BootstrapRunner {
* M4 additions: * M4 additions:
* <ul> * <ul>
* <li>Derives the SQLite JDBC URL from the configured {@code sqlite.file} path.</li> * <li>Derives the SQLite JDBC URL from the configured {@code sqlite.file} path.</li>
* <li>Creates the M4-aware use case via the {@link UseCaseFactory}, which handles * <li>Creates the M4-aware use case via the {@link UseCaseFactory}, which wires persistence ports.</li>
* SQLite schema initialisation and wiring of persistence ports.</li>
* </ul> * </ul>
* *
* @return exit code: 0 for success, 1 for invalid configuration or unexpected bootstrap failure * @return exit code: 0 for success, 1 for invalid configuration or unexpected bootstrap failure
@@ -237,7 +229,7 @@ public class BootstrapRunner {
// Step 6: Create the use case with the validated config and run lock. // Step 6: Create the use case with the validated config and run lock.
// Config is passed directly; the use case does not re-read the properties file. // Config is passed directly; the use case does not re-read the properties file.
// Adapters (source document port, PDF extraction port, M4 ports) are wired by the factory. // Adapters (source document port, PDF extraction port, M4 ports) are wired by the factory.
// Schema initialization happens within the UseCaseFactory. (AP-007 responsibility) // Schema initialization is AP-007 responsibility, not performed in AP-006.
BatchRunProcessingUseCase useCase = useCaseFactory.create(config, runLockPort); BatchRunProcessingUseCase useCase = useCaseFactory.create(config, runLockPort);
// Step 7: Create the CLI command adapter with the use case // Step 7: Create the CLI command adapter with the use case
@@ -269,9 +261,8 @@ public class BootstrapRunner {
LOG.error("Configuration loading failed: {}", e.getMessage()); LOG.error("Configuration loading failed: {}", e.getMessage());
return 1; return 1;
} catch (DocumentPersistenceException e) { } catch (DocumentPersistenceException e) {
// Persistence operation during startup failed hard start error // Persistence operation failed hard error
// (e.g., schema initialisation in UseCaseFactory) LOG.error("Persistence operation failed: {}", e.getMessage(), e);
LOG.error("Persistence operation during startup failed: {}", e.getMessage(), e);
return 1; return 1;
} catch (Exception e) { } catch (Exception e) {
LOG.error("Bootstrap failure during startup.", e); LOG.error("Bootstrap failure during startup.", e);