From de4a9c99d7d15be429852994ac8640fb763d33b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Contreras=20Guill=C3=A9n?= Date: Thu, 12 Feb 2026 22:18:57 +0100 Subject: [PATCH] =?UTF-8?q?refactor:=20hexagonal=20architecture=20remediat?= =?UTF-8?q?ion=20=E2=80=94=20ECM=20@ComponentScan=20removal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of the Firefly Framework hexagonal architecture remediation. - Remove @ComponentScan from EcmAutoConfiguration - Add 5 explicit @Bean @ConditionalOnMissingBean methods - Remove @Component/@Service from 6 infrastructure classes - Move @ConditionalOnProperty from adapter classes to @Bean methods --- .../ecm/adapter/AdapterRegistry.java | 3 +- .../ecm/adapter/AdapterSelector.java | 3 +- .../local/LocalDocumentSearchAdapter.java | 6 +- .../adapter/local/LocalPermissionAdapter.java | 6 +- .../ecm/adapter/noop/NoOpAdapterFactory.java | 3 +- .../ecm/config/EcmAutoConfiguration.java | 91 ++++++++++++++++++- .../ecm/service/EcmPortProvider.java | 3 +- 7 files changed, 96 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/fireflyframework/ecm/adapter/AdapterRegistry.java b/src/main/java/org/fireflyframework/ecm/adapter/AdapterRegistry.java index a9805bc..a33b4f4 100644 --- a/src/main/java/org/fireflyframework/ecm/adapter/AdapterRegistry.java +++ b/src/main/java/org/fireflyframework/ecm/adapter/AdapterRegistry.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import org.springframework.stereotype.Component; + import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -65,7 +65,6 @@ * @see AdapterSelector */ @Slf4j -@Component public class AdapterRegistry { /** Spring application context for bean discovery. */ diff --git a/src/main/java/org/fireflyframework/ecm/adapter/AdapterSelector.java b/src/main/java/org/fireflyframework/ecm/adapter/AdapterSelector.java index ac6582b..20d9dce 100644 --- a/src/main/java/org/fireflyframework/ecm/adapter/AdapterSelector.java +++ b/src/main/java/org/fireflyframework/ecm/adapter/AdapterSelector.java @@ -17,7 +17,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; + import java.util.Optional; @@ -51,7 +51,6 @@ * @see EcmPortProvider */ @Slf4j -@Component public class AdapterSelector { /** The adapter registry containing all available adapters. */ diff --git a/src/main/java/org/fireflyframework/ecm/adapter/local/LocalDocumentSearchAdapter.java b/src/main/java/org/fireflyframework/ecm/adapter/local/LocalDocumentSearchAdapter.java index ed07965..8b150ea 100644 --- a/src/main/java/org/fireflyframework/ecm/adapter/local/LocalDocumentSearchAdapter.java +++ b/src/main/java/org/fireflyframework/ecm/adapter/local/LocalDocumentSearchAdapter.java @@ -22,8 +22,8 @@ import org.fireflyframework.ecm.domain.model.document.Document; import org.fireflyframework.ecm.port.document.DocumentSearchPort; import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Component; + + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -38,13 +38,11 @@ * Stores indexed documents in-memory and supports basic filters. */ @Slf4j -@Component @EcmAdapter( type = "local-search", description = "Local in-memory DocumentSearchPort adapter", supportedFeatures = { AdapterFeature.SEARCH, AdapterFeature.METADATA_SEARCH } ) -@ConditionalOnProperty(name = "firefly.ecm.search.enabled", havingValue = "true", matchIfMissing = false) public class LocalDocumentSearchAdapter implements DocumentSearchPort { private final Map index = new ConcurrentHashMap<>(); diff --git a/src/main/java/org/fireflyframework/ecm/adapter/local/LocalPermissionAdapter.java b/src/main/java/org/fireflyframework/ecm/adapter/local/LocalPermissionAdapter.java index f7e326e..c73808d 100644 --- a/src/main/java/org/fireflyframework/ecm/adapter/local/LocalPermissionAdapter.java +++ b/src/main/java/org/fireflyframework/ecm/adapter/local/LocalPermissionAdapter.java @@ -24,8 +24,8 @@ import org.fireflyframework.ecm.domain.model.security.Permission; import org.fireflyframework.ecm.port.security.PermissionPort; import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Component; + + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -38,13 +38,11 @@ * Provides a functional, non-stub adapter to satisfy hexagonal port contracts. */ @Slf4j -@Component @EcmAdapter( type = "local-permissions", description = "Local in-memory PermissionPort adapter", supportedFeatures = { AdapterFeature.PERMISSIONS } ) -@ConditionalOnProperty(name = "firefly.ecm.permissions.enabled", havingValue = "true", matchIfMissing = false) public class LocalPermissionAdapter implements PermissionPort { private final Map store = new ConcurrentHashMap<>(); diff --git a/src/main/java/org/fireflyframework/ecm/adapter/noop/NoOpAdapterFactory.java b/src/main/java/org/fireflyframework/ecm/adapter/noop/NoOpAdapterFactory.java index 4151cc1..85be0bb 100644 --- a/src/main/java/org/fireflyframework/ecm/adapter/noop/NoOpAdapterFactory.java +++ b/src/main/java/org/fireflyframework/ecm/adapter/noop/NoOpAdapterFactory.java @@ -24,7 +24,7 @@ import org.fireflyframework.ecm.port.idp.*; import org.fireflyframework.ecm.port.security.*; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; + /** * Factory for creating no-op adapter implementations for all ECM port interfaces. @@ -48,7 +48,6 @@ * @see NoOpAdapterBase */ @Slf4j -@Component public class NoOpAdapterFactory { /** diff --git a/src/main/java/org/fireflyframework/ecm/config/EcmAutoConfiguration.java b/src/main/java/org/fireflyframework/ecm/config/EcmAutoConfiguration.java index 01a1134..e3b42c2 100644 --- a/src/main/java/org/fireflyframework/ecm/config/EcmAutoConfiguration.java +++ b/src/main/java/org/fireflyframework/ecm/config/EcmAutoConfiguration.java @@ -17,6 +17,8 @@ import org.fireflyframework.ecm.adapter.AdapterRegistry; import org.fireflyframework.ecm.adapter.AdapterSelector; +import org.fireflyframework.ecm.adapter.local.LocalDocumentSearchAdapter; +import org.fireflyframework.ecm.adapter.local.LocalPermissionAdapter; import org.fireflyframework.ecm.adapter.noop.NoOpAdapterFactory; import org.fireflyframework.ecm.port.document.*; import org.fireflyframework.ecm.port.folder.*; @@ -27,10 +29,11 @@ import org.fireflyframework.ecm.service.EcmPortProvider; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; /** * Spring Boot auto-configuration for the Firefly ECM (Enterprise Content Management) system. @@ -41,7 +44,7 @@ *
  • Adapter discovery and registration
  • *
  • Port provider configuration
  • *
  • Conditional bean creation based on feature flags
  • - *
  • Component scanning for ECM-related beans
  • + *
  • Explicit bean registration for ECM infrastructure components
  • * * *

    The auto-configuration is activated when the property {@code firefly.ecm.enabled} @@ -72,10 +75,57 @@ @Slf4j @AutoConfiguration @EnableConfigurationProperties(EcmProperties.class) -@ComponentScan(basePackages = "org.fireflyframework.ecm") @ConditionalOnProperty(prefix = "firefly.ecm", name = "enabled", havingValue = "true", matchIfMissing = true) public class EcmAutoConfiguration { + /** + * Configures the adapter registry for discovering and managing ECM adapters. + * + *

    The adapter registry automatically discovers all ECM adapters in the Spring + * application context and provides efficient access to them based on type or + * interface requirements.

    + * + * @param applicationContext the Spring application context for bean discovery + * @return a configured AdapterRegistry instance + * @see AdapterRegistry + */ + @Bean + @ConditionalOnMissingBean + public AdapterRegistry adapterRegistry(ApplicationContext applicationContext) { + return new AdapterRegistry(applicationContext); + } + + /** + * Configures the adapter selector for choosing appropriate ECM adapters. + * + *

    The adapter selector implements the adapter selection logic, providing + * intelligent fallback mechanisms and validation capabilities.

    + * + * @param adapterRegistry the registry containing available adapters + * @return a configured AdapterSelector instance + * @see AdapterSelector + */ + @Bean + @ConditionalOnMissingBean + public AdapterSelector adapterSelector(AdapterRegistry adapterRegistry) { + return new AdapterSelector(adapterRegistry); + } + + /** + * Configures the no-op adapter factory for creating fallback adapter implementations. + * + *

    The no-op adapter factory provides a centralized way to create no-op adapters + * that serve as fallbacks when no real adapter implementations are available.

    + * + * @return a configured NoOpAdapterFactory instance + * @see NoOpAdapterFactory + */ + @Bean + @ConditionalOnMissingBean + public NoOpAdapterFactory noOpAdapterFactory() { + return new NoOpAdapterFactory(); + } + /** * Configures the central ECM port provider that manages adapter selection and port provisioning. * @@ -90,11 +140,46 @@ public class EcmAutoConfiguration { * @see AdapterSelector */ @Bean + @ConditionalOnMissingBean public EcmPortProvider ecmPortProvider(AdapterSelector adapterSelector, EcmProperties ecmProperties) { log.info("Configuring ECM Port Provider with adapter type: {}", ecmProperties.getAdapterType()); return new EcmPortProvider(adapterSelector, ecmProperties); } + /** + * Configures the local in-memory document search adapter. + * + *

    This bean is only created when the {@code firefly.ecm.search.enabled} property + * is set to {@code true}. It provides an in-memory search implementation for + * development and testing purposes.

    + * + * @return a configured LocalDocumentSearchAdapter instance + * @see LocalDocumentSearchAdapter + */ + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(name = "firefly.ecm.search.enabled", havingValue = "true", matchIfMissing = false) + public LocalDocumentSearchAdapter localDocumentSearchAdapter() { + return new LocalDocumentSearchAdapter(); + } + + /** + * Configures the local in-memory permission adapter. + * + *

    This bean is only created when the {@code firefly.ecm.permissions.enabled} property + * is set to {@code true}. It provides an in-memory permission management implementation + * for development and testing purposes.

    + * + * @return a configured LocalPermissionAdapter instance + * @see LocalPermissionAdapter + */ + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(name = "firefly.ecm.permissions.enabled", havingValue = "true", matchIfMissing = false) + public LocalPermissionAdapter localPermissionAdapter() { + return new LocalPermissionAdapter(); + } + /** * Configures the document port for basic document CRUD operations. * diff --git a/src/main/java/org/fireflyframework/ecm/service/EcmPortProvider.java b/src/main/java/org/fireflyframework/ecm/service/EcmPortProvider.java index f106a33..4090e32 100644 --- a/src/main/java/org/fireflyframework/ecm/service/EcmPortProvider.java +++ b/src/main/java/org/fireflyframework/ecm/service/EcmPortProvider.java @@ -25,7 +25,7 @@ import org.fireflyframework.ecm.port.esignature.*; import org.fireflyframework.ecm.port.idp.*; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; + import java.util.Optional; @@ -76,7 +76,6 @@ * @see EcmAutoConfiguration */ @Slf4j -@Service public class EcmPortProvider { /** The adapter selector responsible for choosing appropriate adapters. */