diff --git a/application/src/main/java/run/halo/app/content/comment/CommentNotificationReasonPublisher.java b/application/src/main/java/run/halo/app/content/comment/CommentNotificationReasonPublisher.java index 8af96c597..386848250 100644 --- a/application/src/main/java/run/halo/app/content/comment/CommentNotificationReasonPublisher.java +++ b/application/src/main/java/run/halo/app/content/comment/CommentNotificationReasonPublisher.java @@ -30,7 +30,6 @@ import run.halo.app.extension.Ref; import run.halo.app.infra.ExternalLinkProcessor; import run.halo.app.infra.utils.JsonUtils; import run.halo.app.notification.NotificationReasonEmitter; -import run.halo.app.plugin.ExtensionComponentsFinder; import run.halo.app.plugin.extensionpoint.ExtensionGetter; /** @@ -233,7 +232,7 @@ public class CommentNotificationReasonPublisher { static class NewReplyReasonPublisher { private final ExtensionClient client; private final NotificationReasonEmitter notificationReasonEmitter; - private final ExtensionComponentsFinder extensionComponentsFinder; + private final ExtensionGetter extensionGetter; public void publishReasonBy(Reply reply, Comment comment) { boolean isQuoteReply = StringUtils.isNotBlank(reply.getSpec().getQuoteReply()); @@ -306,16 +305,14 @@ public class CommentNotificationReasonPublisher { /** * To be compatible with older versions, it may be empty, so use optional. - * TODO use {@link ExtensionGetter} instead of {@code extensionComponentsFinder} */ @SuppressWarnings("unchecked") Optional getCommentSubjectDisplay(Ref ref) { - return extensionComponentsFinder.getExtensions(CommentSubject.class) - .stream() + return extensionGetter.getExtensions(CommentSubject.class) .filter(commentSubject -> commentSubject.supports(ref)) - .findFirst() - .flatMap(commentSubject - -> commentSubject.getSubjectDisplay(ref.getName()).blockOptional()); + .next() + .flatMap(subject -> subject.getSubjectDisplay(ref.getName())) + .blockOptional(); } boolean doNotEmitReason(Reply currentReply, Reply quoteReply, Comment comment) { diff --git a/application/src/main/java/run/halo/app/content/comment/CommentServiceImpl.java b/application/src/main/java/run/halo/app/content/comment/CommentServiceImpl.java index 217eb5734..d32931c14 100644 --- a/application/src/main/java/run/halo/app/content/comment/CommentServiceImpl.java +++ b/application/src/main/java/run/halo/app/content/comment/CommentServiceImpl.java @@ -34,7 +34,7 @@ import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.exception.AccessDeniedException; import run.halo.app.metrics.CounterService; import run.halo.app.metrics.MeterUtils; -import run.halo.app.plugin.ExtensionComponentsFinder; +import run.halo.app.plugin.extensionpoint.ExtensionGetter; import run.halo.app.security.authorization.AuthorityUtils; /** @@ -49,22 +49,23 @@ public class CommentServiceImpl implements CommentService { private final ReactiveExtensionClient client; private final UserService userService; private final RoleService roleService; - private final ExtensionComponentsFinder extensionComponentsFinder; + private final ExtensionGetter extensionGetter; private final SystemConfigurableEnvironmentFetcher environmentFetcher; private final CounterService counterService; public CommentServiceImpl(ReactiveExtensionClient client, - UserService userService, ExtensionComponentsFinder extensionComponentsFinder, + UserService userService, SystemConfigurableEnvironmentFetcher environmentFetcher, - CounterService counterService, RoleService roleService + CounterService counterService, RoleService roleService, + ExtensionGetter extensionGetter ) { this.client = client; this.userService = userService; - this.extensionComponentsFinder = extensionComponentsFinder; this.environmentFetcher = environmentFetcher; this.counterService = counterService; this.roleService = roleService; + this.extensionGetter = extensionGetter; } @Override @@ -247,11 +248,9 @@ public class CommentServiceImpl implements CommentService { @SuppressWarnings("unchecked") Mono getCommentSubject(Ref ref) { - return extensionComponentsFinder.getExtensions(CommentSubject.class) - .stream() - .filter(commentSubject -> commentSubject.supports(ref)) - .findFirst() - .map(commentSubject -> commentSubject.get(ref.getName())) - .orElseGet(Mono::empty); + return extensionGetter.getExtensions(CommentSubject.class) + .filter(subject -> subject.supports(ref)) + .next() + .flatMap(subject -> subject.get(ref.getName())); } } diff --git a/application/src/main/java/run/halo/app/core/extension/service/impl/DefaultAttachmentService.java b/application/src/main/java/run/halo/app/core/extension/service/impl/DefaultAttachmentService.java index f66be7f7c..27c885ebc 100644 --- a/application/src/main/java/run/halo/app/core/extension/service/impl/DefaultAttachmentService.java +++ b/application/src/main/java/run/halo/app/core/extension/service/impl/DefaultAttachmentService.java @@ -29,19 +29,19 @@ import run.halo.app.core.extension.attachment.endpoint.UploadOption; import run.halo.app.core.extension.service.AttachmentService; import run.halo.app.extension.ConfigMap; import run.halo.app.extension.ReactiveExtensionClient; -import run.halo.app.plugin.ExtensionComponentsFinder; +import run.halo.app.plugin.extensionpoint.ExtensionGetter; @Component public class DefaultAttachmentService implements AttachmentService { private final ReactiveExtensionClient client; - private final ExtensionComponentsFinder extensionComponentsFinder; + private final ExtensionGetter extensionGetter; public DefaultAttachmentService(ReactiveExtensionClient client, - ExtensionComponentsFinder extensionComponentsFinder) { + ExtensionGetter extensionGetter) { this.client = client; - this.extensionComponentsFinder = extensionComponentsFinder; + this.extensionGetter = extensionGetter; } @Override @@ -61,12 +61,9 @@ public class DefaultAttachmentService implements AttachmentService { return client.get(ConfigMap.class, configMapName) .map(configMap -> new UploadOption(filePart, policy, configMap)); }) - .flatMap(uploadContext -> { - var handlers = extensionComponentsFinder.getExtensions(AttachmentHandler.class); - return Flux.fromIterable(handlers) - .concatMap(handler -> handler.upload(uploadContext)) - .next(); - }) + .flatMap(uploadContext -> extensionGetter.getExtensions(AttachmentHandler.class) + .concatMap(handler -> handler.upload(uploadContext)) + .next()) .switchIfEmpty(Mono.error(() -> new ServerErrorException( "No suitable handler found for uploading the attachment.", null))) .doOnNext(attachment -> { @@ -106,32 +103,31 @@ public class DefaultAttachmentService implements AttachmentService { return client.get(Policy.class, spec.getPolicyName()) .flatMap(policy -> client.get(ConfigMap.class, policy.getSpec().getConfigMapName()) .map(configMap -> new DeleteOption(attachment, policy, configMap))) - .flatMap(deleteOption -> { - var handlers = extensionComponentsFinder.getExtensions(AttachmentHandler.class); - return Flux.fromIterable(handlers) - .concatMap(handler -> handler.delete(deleteOption)) - .next(); - }); + .flatMap(deleteOption -> extensionGetter.getExtensions(AttachmentHandler.class) + .concatMap(handler -> handler.delete(deleteOption)) + .next()); } @Override public Mono getPermalink(Attachment attachment) { - var handlers = extensionComponentsFinder.getExtensions(AttachmentHandler.class); return client.get(Policy.class, attachment.getSpec().getPolicyName()) .flatMap(policy -> client.get(ConfigMap.class, policy.getSpec().getConfigMapName()) - .flatMap(configMap -> Flux.fromIterable(handlers) + .flatMap(configMap -> extensionGetter.getExtensions(AttachmentHandler.class) .concatMap(handler -> handler.getPermalink(attachment, policy, configMap)) - .next())); + .next() + ) + ); } @Override public Mono getSharedURL(Attachment attachment, Duration ttl) { - var handlers = extensionComponentsFinder.getExtensions(AttachmentHandler.class); return client.get(Policy.class, attachment.getSpec().getPolicyName()) .flatMap(policy -> client.get(ConfigMap.class, policy.getSpec().getConfigMapName()) - .flatMap(configMap -> Flux.fromIterable(handlers) + .flatMap(configMap -> extensionGetter.getExtensions(AttachmentHandler.class) .concatMap(handler -> handler.getSharedURL(attachment, policy, configMap, ttl)) - .next())); + .next() + ) + ); } private Mono authenticationConsumer(Function> func) { diff --git a/application/src/main/java/run/halo/app/plugin/ExtensionComponentsFinder.java b/application/src/main/java/run/halo/app/plugin/ExtensionComponentsFinder.java deleted file mode 100644 index c08946884..000000000 --- a/application/src/main/java/run/halo/app/plugin/ExtensionComponentsFinder.java +++ /dev/null @@ -1,68 +0,0 @@ -package run.halo.app.plugin; - -import java.util.ArrayList; -import java.util.List; -import org.pf4j.ExtensionPoint; -import org.pf4j.PluginManager; -import org.springframework.context.ApplicationContext; -import org.springframework.stereotype.Component; - -/** - * Extension components finder for {@link ExtensionPoint}. - * - * @author guqing - * @since 2.0.0 - */ -@Component -@Deprecated(forRemoval = true) -public class ExtensionComponentsFinder { - public static final String SYSTEM_PLUGIN_ID = "system"; - private final PluginManager pluginManager; - private final ApplicationContext applicationContext; - - public ExtensionComponentsFinder(PluginManager pluginManager, - ApplicationContext applicationContext) { - this.pluginManager = pluginManager; - this.applicationContext = applicationContext; - } - - /** - * Finds all extension components. - * - * @param type subclass type of extension point - * @param extension component type - * @return extension components - */ - public List getExtensions(Class type) { - assertExtensionPoint(type); - List components = new ArrayList<>(pluginManager.getExtensions(type)); - components.addAll(applicationContext.getBeansOfType(type).values()); - return List.copyOf(components); - } - - /** - *

Finds all extension components by plugin id.

- * If the plugin id is system or null, it means to find from halo. - * - * @param type subclass type of extension point - * @param extension component type - * @return extension components - */ - public List getExtensions(Class type, String pluginId) { - assertExtensionPoint(type); - List components = new ArrayList<>(); - if (pluginId == null || SYSTEM_PLUGIN_ID.equals(pluginId)) { - components.addAll(applicationContext.getBeansOfType(type).values()); - return components; - } else { - components.addAll(pluginManager.getExtensions(type, pluginId)); - } - return components; - } - - private void assertExtensionPoint(Class type) { - if (!ExtensionPoint.class.isAssignableFrom(type)) { - throw new IllegalArgumentException("The type must be a subclass of ExtensionPoint"); - } - } -} diff --git a/application/src/main/java/run/halo/app/theme/dialect/GlobalHeadInjectionProcessor.java b/application/src/main/java/run/halo/app/theme/dialect/GlobalHeadInjectionProcessor.java index b4be9c7a7..6be5c52bb 100644 --- a/application/src/main/java/run/halo/app/theme/dialect/GlobalHeadInjectionProcessor.java +++ b/application/src/main/java/run/halo/app/theme/dialect/GlobalHeadInjectionProcessor.java @@ -1,16 +1,15 @@ package run.halo.app.theme.dialect; -import java.util.Collection; -import org.springframework.context.ApplicationContext; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import static org.thymeleaf.spring6.context.SpringContextUtils.getApplicationContext; + import org.thymeleaf.context.ITemplateContext; import org.thymeleaf.model.IModel; import org.thymeleaf.model.ITemplateEvent; import org.thymeleaf.processor.element.AbstractElementModelProcessor; import org.thymeleaf.processor.element.IElementModelStructureHandler; -import org.thymeleaf.spring6.context.SpringContextUtils; import org.thymeleaf.templatemode.TemplateMode; -import run.halo.app.plugin.ExtensionComponentsFinder; +import reactor.core.publisher.Flux; +import run.halo.app.plugin.extensionpoint.ExtensionGetter; /** * Global head injection processor. @@ -71,13 +70,10 @@ public class GlobalHeadInjectionProcessor extends AbstractElementModelProcessor modelToInsert.remove(0); // apply processors to modelToInsert - Collection templateHeadProcessors = - getTemplateHeadProcessors(context); - - for (TemplateHeadProcessor processor : templateHeadProcessors) { - processor.process(context, modelToInsert, structureHandler) - .block(); - } + getTemplateHeadProcessors(context) + .concatMap(processor -> processor.process(context, modelToInsert, structureHandler)) + .then() + .block(); // reset model to insert model.reset(); @@ -86,13 +82,12 @@ public class GlobalHeadInjectionProcessor extends AbstractElementModelProcessor model.add(closeHeadTag); } - private Collection getTemplateHeadProcessors(ITemplateContext context) { - ApplicationContext appCtx = SpringContextUtils.getApplicationContext(context); - ExtensionComponentsFinder componentsFinder = - appCtx.getBean(ExtensionComponentsFinder.class); - return componentsFinder.getExtensions(TemplateHeadProcessor.class) - .stream() - .sorted(AnnotationAwareOrderComparator.INSTANCE) - .toList(); + private Flux getTemplateHeadProcessors(ITemplateContext context) { + var extensionGetter = getApplicationContext(context).getBeanProvider(ExtensionGetter.class) + .getIfUnique(); + if (extensionGetter == null) { + return Flux.empty(); + } + return extensionGetter.getExtensions(TemplateHeadProcessor.class); } } diff --git a/application/src/test/java/run/halo/app/content/comment/CommentNotificationReasonPublisherTest.java b/application/src/test/java/run/halo/app/content/comment/CommentNotificationReasonPublisherTest.java index 7f854d506..44ae34248 100644 --- a/application/src/test/java/run/halo/app/content/comment/CommentNotificationReasonPublisherTest.java +++ b/application/src/test/java/run/halo/app/content/comment/CommentNotificationReasonPublisherTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import run.halo.app.content.NotificationReasonConst; import run.halo.app.core.extension.User; @@ -36,7 +37,7 @@ import run.halo.app.infra.ExternalLinkProcessor; import run.halo.app.notification.NotificationReasonEmitter; import run.halo.app.notification.ReasonPayload; import run.halo.app.notification.UserIdentity; -import run.halo.app.plugin.ExtensionComponentsFinder; +import run.halo.app.plugin.extensionpoint.ExtensionGetter; /** * Tests for {@link CommentNotificationReasonPublisher}. @@ -143,7 +144,7 @@ class CommentNotificationReasonPublisherTest { NotificationReasonEmitter emitter; @Mock - ExtensionComponentsFinder extensionComponentsFinder; + ExtensionGetter extensionGetter; @Mock ExternalLinkProcessor externalLinkProcessor; @@ -248,9 +249,6 @@ class CommentNotificationReasonPublisherTest { @Mock NotificationReasonEmitter emitter; - @Mock - ExtensionComponentsFinder extensionComponentsFinder; - @Mock ExternalLinkProcessor externalLinkProcessor; @@ -358,13 +356,15 @@ class CommentNotificationReasonPublisherTest { NotificationReasonEmitter notificationReasonEmitter; @Mock - ExtensionComponentsFinder extensionComponentsFinder; + ExtensionGetter extensionGetter; @InjectMocks CommentNotificationReasonPublisher.NewReplyReasonPublisher newReplyReasonPublisher; @Test void publishReasonByTest() { + when(extensionGetter.getExtensions(CommentSubject.class)) + .thenReturn(Flux.empty()); var reply = createReply("fake-reply"); reply.getSpec().setQuoteReply("fake-quote-reply"); diff --git a/application/src/test/java/run/halo/app/content/comment/CommentServiceImplTest.java b/application/src/test/java/run/halo/app/content/comment/CommentServiceImplTest.java index e0c9d06fb..ac23f1e13 100644 --- a/application/src/test/java/run/halo/app/content/comment/CommentServiceImplTest.java +++ b/application/src/test/java/run/halo/app/content/comment/CommentServiceImplTest.java @@ -27,6 +27,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import run.halo.app.content.TestPost; @@ -47,7 +48,7 @@ import run.halo.app.infra.SystemSetting; import run.halo.app.infra.utils.JsonUtils; import run.halo.app.metrics.CounterService; import run.halo.app.metrics.MeterUtils; -import run.halo.app.plugin.ExtensionComponentsFinder; +import run.halo.app.plugin.extensionpoint.ExtensionGetter; import run.halo.app.security.authorization.AuthorityUtils; /** @@ -72,7 +73,7 @@ class CommentServiceImplTest { private RoleService roleService; @Mock - private ExtensionComponentsFinder extensionComponentsFinder; + private ExtensionGetter extensionGetter; @InjectMocks private CommentServiceImpl commentService; @@ -101,8 +102,8 @@ class CommentServiceImplTest { .thenReturn(Mono.just(false)); PostCommentSubject postCommentSubject = Mockito.mock(PostCommentSubject.class); - when(extensionComponentsFinder.getExtensions(eq(CommentSubject.class))) - .thenReturn(List.of(postCommentSubject)); + when(extensionGetter.getExtensions(CommentSubject.class)) + .thenReturn(Flux.just(postCommentSubject)); when(postCommentSubject.supports(any())).thenReturn(true); when(postCommentSubject.get(eq("fake-post"))).thenReturn(Mono.just(post())); diff --git a/application/src/test/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpointTest.java b/application/src/test/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpointTest.java index 7736c42b2..e3c7fa4a7 100644 --- a/application/src/test/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpointTest.java +++ b/application/src/test/java/run/halo/app/core/extension/attachment/endpoint/AttachmentEndpointTest.java @@ -10,7 +10,6 @@ import static org.mockito.Mockito.when; import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockUser; import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity; -import java.util.List; import java.util.Map; import java.util.function.Consumer; import org.junit.jupiter.api.BeforeEach; @@ -36,7 +35,7 @@ import run.halo.app.extension.ListResult; import run.halo.app.extension.Metadata; import run.halo.app.extension.PageRequest; import run.halo.app.extension.ReactiveExtensionClient; -import run.halo.app.plugin.ExtensionComponentsFinder; +import run.halo.app.plugin.extensionpoint.ExtensionGetter; @ExtendWith(MockitoExtension.class) class AttachmentEndpointTest { @@ -45,7 +44,7 @@ class AttachmentEndpointTest { ReactiveExtensionClient client; @Mock - ExtensionComponentsFinder extensionComponentsFinder; + ExtensionGetter extensionGetter; AttachmentEndpoint endpoint; @@ -53,7 +52,7 @@ class AttachmentEndpointTest { @BeforeEach void setUp() { - var attachmentService = new DefaultAttachmentService(client, extensionComponentsFinder); + var attachmentService = new DefaultAttachmentService(client, extensionGetter); endpoint = new AttachmentEndpoint(attachmentService, client); webClient = WebTestClient.bindToRouterFunction(endpoint.endpoint()) .apply(springSecurity()) @@ -101,7 +100,7 @@ class AttachmentEndpointTest { verify(client, never()).get(Policy.class, "fake-policy"); verify(client, never()).get(ConfigMap.class, "fake-configmap"); verify(client, never()).create(attachment); - verify(extensionComponentsFinder, never()).getExtensions(AttachmentHandler.class); + verify(extensionGetter, never()).getExtensions(AttachmentHandler.class); verify(handler, never()).upload(any()); } @@ -156,8 +155,8 @@ class AttachmentEndpointTest { attachment.setMetadata(metadata); when(handler.upload(any())).thenReturn(Mono.just(attachment)); - when(extensionComponentsFinder.getExtensions(AttachmentHandler.class)).thenReturn( - List.of(handler)); + when(extensionGetter.getExtensions(AttachmentHandler.class)) + .thenReturn(Flux.just(handler)); when(client.create(attachment)).thenReturn(Mono.just(attachment)); var builder = new MultipartBodyBuilder(); @@ -195,8 +194,8 @@ class AttachmentEndpointTest { attachment.setMetadata(metadata); when(handler.upload(any())).thenReturn(Mono.just(attachment)); - when(extensionComponentsFinder.getExtensions(AttachmentHandler.class)).thenReturn( - List.of(handler)); + when(extensionGetter.getExtensions(AttachmentHandler.class)) + .thenReturn(Flux.just(handler)); when(client.create(attachment)).thenReturn(Mono.just(attachment)); var builder = new MultipartBodyBuilder(); @@ -223,7 +222,6 @@ class AttachmentEndpointTest { verify(client).get(Policy.class, "fake-policy"); verify(client).get(ConfigMap.class, "fake-configmap"); verify(client).create(attachment); - verify(extensionComponentsFinder).getExtensions(AttachmentHandler.class); verify(handler).upload(any()); } } diff --git a/application/src/test/java/run/halo/app/theme/dialect/CommentElementTagProcessorTest.java b/application/src/test/java/run/halo/app/theme/dialect/CommentElementTagProcessorTest.java index 52a540e76..2a0726b2e 100644 --- a/application/src/test/java/run/halo/app/theme/dialect/CommentElementTagProcessorTest.java +++ b/application/src/test/java/run/halo/app/theme/dialect/CommentElementTagProcessorTest.java @@ -29,7 +29,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemSetting; -import run.halo.app.plugin.ExtensionComponentsFinder; import run.halo.app.plugin.extensionpoint.ExtensionGetter; /** diff --git a/application/src/test/java/run/halo/app/theme/dialect/ContentTemplateHeadProcessorIntegrationTest.java b/application/src/test/java/run/halo/app/theme/dialect/ContentTemplateHeadProcessorIntegrationTest.java index b7683ae4d..2ab16d454 100644 --- a/application/src/test/java/run/halo/app/theme/dialect/ContentTemplateHeadProcessorIntegrationTest.java +++ b/application/src/test/java/run/halo/app/theme/dialect/ContentTemplateHeadProcessorIntegrationTest.java @@ -3,6 +3,7 @@ package run.halo.app.theme.dialect; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.ArrayList; @@ -16,7 +17,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.thymeleaf.IEngineConfiguration; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; @@ -25,12 +28,13 @@ import org.thymeleaf.spring6.expression.ThymeleafEvaluationContext; import org.thymeleaf.templateresolver.StringTemplateResolver; import org.thymeleaf.templateresource.ITemplateResource; import org.thymeleaf.templateresource.StringTemplateResource; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import run.halo.app.core.extension.content.Post; import run.halo.app.extension.Metadata; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemSetting; -import run.halo.app.plugin.ExtensionComponentsFinder; +import run.halo.app.plugin.extensionpoint.ExtensionGetter; import run.halo.app.theme.DefaultTemplateEnum; import run.halo.app.theme.finders.PostFinder; import run.halo.app.theme.finders.SinglePageFinder; @@ -64,7 +68,7 @@ class ContentTemplateHeadProcessorIntegrationTest { private SystemConfigurableEnvironmentFetcher fetcher; @Mock - private ExtensionComponentsFinder extensionComponentsFinder; + ExtensionGetter extensionGetter; private TemplateEngine templateEngine; @@ -98,17 +102,18 @@ class ContentTemplateHeadProcessorIntegrationTest { lenient().when(fetcher.fetch(eq(SystemSetting.CodeInjection.GROUP), eq(SystemSetting.CodeInjection.class))).thenReturn(Mono.just(codeInjection)); - lenient().when(applicationContext.getBean(eq(SystemConfigurableEnvironmentFetcher.class))) - .thenReturn(fetcher); lenient().when(fetcher.fetch(eq(SystemSetting.Seo.GROUP), eq(SystemSetting.Seo.class))) .thenReturn(Mono.empty()); - lenient().when(applicationContext.getBean(eq(ExtensionComponentsFinder.class))) - .thenReturn(extensionComponentsFinder); - - lenient().when(extensionComponentsFinder.getExtensions(eq(TemplateHeadProcessor.class))) - .thenReturn(new ArrayList<>(map.values())); - + lenient().when(applicationContext.getBeanProvider(ExtensionGetter.class)) + .thenAnswer(invocation -> { + var objectProvider = mock(ObjectProvider.class); + when(objectProvider.getIfUnique()).thenReturn(extensionGetter); + return objectProvider; + }); + lenient().when(extensionGetter.getExtensions(TemplateHeadProcessor.class)).thenReturn( + Flux.fromIterable(map.values()).sort(AnnotationAwareOrderComparator.INSTANCE) + ); lenient().when(applicationContext.getBean(eq(SystemConfigurableEnvironmentFetcher.class))) .thenReturn(fetcher); lenient().when(fetcher.fetchComment()).thenReturn(Mono.just(new SystemSetting.Comment())); diff --git a/application/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java b/application/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java index 178b6abde..d0a36706b 100644 --- a/application/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java +++ b/application/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java @@ -3,6 +3,7 @@ package run.halo.app.theme.dialect; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableSortedMap; @@ -17,7 +18,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.thymeleaf.IEngineConfiguration; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; @@ -26,13 +29,16 @@ import org.thymeleaf.spring6.expression.ThymeleafEvaluationContext; import org.thymeleaf.templateresolver.StringTemplateResolver; import org.thymeleaf.templateresource.ITemplateResource; import org.thymeleaf.templateresource.StringTemplateResource; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import run.halo.app.core.extension.User; import run.halo.app.core.extension.content.Post; import run.halo.app.extension.Metadata; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemSetting; -import run.halo.app.plugin.ExtensionComponentsFinder; +import run.halo.app.infra.SystemSetting.CodeInjection; +import run.halo.app.infra.SystemSetting.Seo; +import run.halo.app.plugin.extensionpoint.ExtensionGetter; import run.halo.app.theme.DefaultTemplateEnum; import run.halo.app.theme.finders.PostFinder; import run.halo.app.theme.finders.SinglePageFinder; @@ -67,7 +73,7 @@ class HaloProcessorDialectTest { private SystemConfigurableEnvironmentFetcher fetcher; @Mock - private ExtensionComponentsFinder extensionComponentsFinder; + ExtensionGetter extensionGetter; private TemplateEngine templateEngine; @@ -84,29 +90,30 @@ class HaloProcessorDialectTest { map.put("templateGlobalHeadProcessor", new TemplateGlobalHeadProcessor(fetcher)); map.put("faviconHeadProcessor", new DefaultFaviconHeadProcessor(fetcher)); map.put("globalSeoProcessor", new GlobalSeoProcessor(fetcher)); - lenient().when(applicationContext.getBeansOfType(eq(TemplateHeadProcessor.class))) - .thenReturn(map); - SystemSetting.CodeInjection codeInjection = new SystemSetting.CodeInjection(); + CodeInjection codeInjection = new CodeInjection(); codeInjection.setContentHead(""); codeInjection.setGlobalHead(""); codeInjection.setFooter("
hello this is global footer.
"); - lenient().when(fetcher.fetch(eq(SystemSetting.CodeInjection.GROUP), - eq(SystemSetting.CodeInjection.class))).thenReturn(Mono.just(codeInjection)); + lenient().when(fetcher.fetch(eq(CodeInjection.GROUP), eq(CodeInjection.class))) + .thenReturn(Mono.just(codeInjection)); lenient().when(applicationContext.getBean(eq(SystemConfigurableEnvironmentFetcher.class))) .thenReturn(fetcher); - lenient().when(fetcher.fetch(eq(SystemSetting.Seo.GROUP), - eq(SystemSetting.Seo.class))).thenReturn(Mono.empty()); + lenient().when(fetcher.fetch(eq(Seo.GROUP), eq(Seo.class))) + .thenReturn(Mono.empty()); - lenient().when(applicationContext.getBean(eq(ExtensionComponentsFinder.class))) - .thenReturn(extensionComponentsFinder); + lenient().when(applicationContext.getBeanProvider(ExtensionGetter.class)) + .then(invocation -> { + @SuppressWarnings("unchecked") + ObjectProvider objectProvider = mock(ObjectProvider.class); + when(objectProvider.getIfUnique()).thenReturn(extensionGetter); + return objectProvider; + }); + lenient().when(extensionGetter.getExtensions(TemplateHeadProcessor.class)).thenReturn( + Flux.fromIterable(map.values()).sort(AnnotationAwareOrderComparator.INSTANCE) + ); - lenient().when(extensionComponentsFinder.getExtensions(eq(TemplateHeadProcessor.class))) - .thenReturn(new ArrayList<>(map.values())); - - lenient().when(applicationContext.getBean(eq(SystemConfigurableEnvironmentFetcher.class))) - .thenReturn(fetcher); lenient().when(fetcher.fetchComment()) .thenReturn(Mono.just(new SystemSetting.Comment())); } @@ -192,10 +199,10 @@ class HaloProcessorDialectTest { @Test void blockSeo() { final Context context = getContext(); - SystemSetting.Seo seo = new SystemSetting.Seo(); + Seo seo = new Seo(); seo.setBlockSpiders(true); - when(fetcher.fetch(eq(SystemSetting.Seo.GROUP), - eq(SystemSetting.Seo.class))).thenReturn(Mono.just(seo)); + when(fetcher.fetch(eq(Seo.GROUP), + eq(Seo.class))).thenReturn(Mono.just(seo)); SystemSetting.Basic basic = new SystemSetting.Basic(); basic.setFavicon("favicon.ico"); when(fetcher.fetch(eq(SystemSetting.Basic.GROUP), @@ -222,11 +229,11 @@ class HaloProcessorDialectTest { @Test void seoWithKeywordsAndDescription() { final Context context = getContext(); - SystemSetting.Seo seo = new SystemSetting.Seo(); + Seo seo = new Seo(); seo.setKeywords("K1, K2, K3"); seo.setDescription("This is a description."); - when(fetcher.fetch(eq(SystemSetting.Seo.GROUP), - eq(SystemSetting.Seo.class))).thenReturn(Mono.just(seo)); + when(fetcher.fetch(eq(Seo.GROUP), + eq(Seo.class))).thenReturn(Mono.just(seo)); SystemSetting.Basic basic = new SystemSetting.Basic(); basic.setFavicon("favicon.ico"); when(fetcher.fetch(eq(SystemSetting.Basic.GROUP),