Remove deprecated ExtensionComponentsFinder (#6185)

#### What type of PR is this?

/kind cleanup
/area core
/milestone 2.17.x

#### What this PR does / why we need it:

In <https://github.com/halo-dev/halo/pull/5386>, I marked ExtensionComponentsFinder as deprecated. Four months have passed, it's time to remove it.

#### Does this PR introduce a user-facing change?

```release-note
None
```
pull/6190/head
John Niang 2024-06-28 10:40:57 +08:00 committed by GitHub
parent 0ddc4f8d42
commit f936e131c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 111 additions and 182 deletions

View File

@ -30,7 +30,6 @@ import run.halo.app.extension.Ref;
import run.halo.app.infra.ExternalLinkProcessor; import run.halo.app.infra.ExternalLinkProcessor;
import run.halo.app.infra.utils.JsonUtils; import run.halo.app.infra.utils.JsonUtils;
import run.halo.app.notification.NotificationReasonEmitter; import run.halo.app.notification.NotificationReasonEmitter;
import run.halo.app.plugin.ExtensionComponentsFinder;
import run.halo.app.plugin.extensionpoint.ExtensionGetter; import run.halo.app.plugin.extensionpoint.ExtensionGetter;
/** /**
@ -233,7 +232,7 @@ public class CommentNotificationReasonPublisher {
static class NewReplyReasonPublisher { static class NewReplyReasonPublisher {
private final ExtensionClient client; private final ExtensionClient client;
private final NotificationReasonEmitter notificationReasonEmitter; private final NotificationReasonEmitter notificationReasonEmitter;
private final ExtensionComponentsFinder extensionComponentsFinder; private final ExtensionGetter extensionGetter;
public void publishReasonBy(Reply reply, Comment comment) { public void publishReasonBy(Reply reply, Comment comment) {
boolean isQuoteReply = StringUtils.isNotBlank(reply.getSpec().getQuoteReply()); 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. * To be compatible with older versions, it may be empty, so use optional.
* TODO use {@link ExtensionGetter} instead of {@code extensionComponentsFinder}
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Optional<CommentSubject.SubjectDisplay> getCommentSubjectDisplay(Ref ref) { Optional<CommentSubject.SubjectDisplay> getCommentSubjectDisplay(Ref ref) {
return extensionComponentsFinder.getExtensions(CommentSubject.class) return extensionGetter.getExtensions(CommentSubject.class)
.stream()
.filter(commentSubject -> commentSubject.supports(ref)) .filter(commentSubject -> commentSubject.supports(ref))
.findFirst() .next()
.flatMap(commentSubject .flatMap(subject -> subject.getSubjectDisplay(ref.getName()))
-> commentSubject.getSubjectDisplay(ref.getName()).blockOptional()); .blockOptional();
} }
boolean doNotEmitReason(Reply currentReply, Reply quoteReply, Comment comment) { boolean doNotEmitReason(Reply currentReply, Reply quoteReply, Comment comment) {

View File

@ -34,7 +34,7 @@ import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
import run.halo.app.infra.exception.AccessDeniedException; import run.halo.app.infra.exception.AccessDeniedException;
import run.halo.app.metrics.CounterService; import run.halo.app.metrics.CounterService;
import run.halo.app.metrics.MeterUtils; 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; import run.halo.app.security.authorization.AuthorityUtils;
/** /**
@ -49,22 +49,23 @@ public class CommentServiceImpl implements CommentService {
private final ReactiveExtensionClient client; private final ReactiveExtensionClient client;
private final UserService userService; private final UserService userService;
private final RoleService roleService; private final RoleService roleService;
private final ExtensionComponentsFinder extensionComponentsFinder; private final ExtensionGetter extensionGetter;
private final SystemConfigurableEnvironmentFetcher environmentFetcher; private final SystemConfigurableEnvironmentFetcher environmentFetcher;
private final CounterService counterService; private final CounterService counterService;
public CommentServiceImpl(ReactiveExtensionClient client, public CommentServiceImpl(ReactiveExtensionClient client,
UserService userService, ExtensionComponentsFinder extensionComponentsFinder, UserService userService,
SystemConfigurableEnvironmentFetcher environmentFetcher, SystemConfigurableEnvironmentFetcher environmentFetcher,
CounterService counterService, RoleService roleService CounterService counterService, RoleService roleService,
ExtensionGetter extensionGetter
) { ) {
this.client = client; this.client = client;
this.userService = userService; this.userService = userService;
this.extensionComponentsFinder = extensionComponentsFinder;
this.environmentFetcher = environmentFetcher; this.environmentFetcher = environmentFetcher;
this.counterService = counterService; this.counterService = counterService;
this.roleService = roleService; this.roleService = roleService;
this.extensionGetter = extensionGetter;
} }
@Override @Override
@ -247,11 +248,9 @@ public class CommentServiceImpl implements CommentService {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Mono<Extension> getCommentSubject(Ref ref) { Mono<Extension> getCommentSubject(Ref ref) {
return extensionComponentsFinder.getExtensions(CommentSubject.class) return extensionGetter.getExtensions(CommentSubject.class)
.stream() .filter(subject -> subject.supports(ref))
.filter(commentSubject -> commentSubject.supports(ref)) .next()
.findFirst() .flatMap(subject -> subject.get(ref.getName()));
.map(commentSubject -> commentSubject.get(ref.getName()))
.orElseGet(Mono::empty);
} }
} }

View File

@ -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.core.extension.service.AttachmentService;
import run.halo.app.extension.ConfigMap; import run.halo.app.extension.ConfigMap;
import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.plugin.ExtensionComponentsFinder; import run.halo.app.plugin.extensionpoint.ExtensionGetter;
@Component @Component
public class DefaultAttachmentService implements AttachmentService { public class DefaultAttachmentService implements AttachmentService {
private final ReactiveExtensionClient client; private final ReactiveExtensionClient client;
private final ExtensionComponentsFinder extensionComponentsFinder; private final ExtensionGetter extensionGetter;
public DefaultAttachmentService(ReactiveExtensionClient client, public DefaultAttachmentService(ReactiveExtensionClient client,
ExtensionComponentsFinder extensionComponentsFinder) { ExtensionGetter extensionGetter) {
this.client = client; this.client = client;
this.extensionComponentsFinder = extensionComponentsFinder; this.extensionGetter = extensionGetter;
} }
@Override @Override
@ -61,12 +61,9 @@ public class DefaultAttachmentService implements AttachmentService {
return client.get(ConfigMap.class, configMapName) return client.get(ConfigMap.class, configMapName)
.map(configMap -> new UploadOption(filePart, policy, configMap)); .map(configMap -> new UploadOption(filePart, policy, configMap));
}) })
.flatMap(uploadContext -> { .flatMap(uploadContext -> extensionGetter.getExtensions(AttachmentHandler.class)
var handlers = extensionComponentsFinder.getExtensions(AttachmentHandler.class);
return Flux.fromIterable(handlers)
.concatMap(handler -> handler.upload(uploadContext)) .concatMap(handler -> handler.upload(uploadContext))
.next(); .next())
})
.switchIfEmpty(Mono.error(() -> new ServerErrorException( .switchIfEmpty(Mono.error(() -> new ServerErrorException(
"No suitable handler found for uploading the attachment.", null))) "No suitable handler found for uploading the attachment.", null)))
.doOnNext(attachment -> { .doOnNext(attachment -> {
@ -106,32 +103,31 @@ public class DefaultAttachmentService implements AttachmentService {
return client.get(Policy.class, spec.getPolicyName()) return client.get(Policy.class, spec.getPolicyName())
.flatMap(policy -> client.get(ConfigMap.class, policy.getSpec().getConfigMapName()) .flatMap(policy -> client.get(ConfigMap.class, policy.getSpec().getConfigMapName())
.map(configMap -> new DeleteOption(attachment, policy, configMap))) .map(configMap -> new DeleteOption(attachment, policy, configMap)))
.flatMap(deleteOption -> { .flatMap(deleteOption -> extensionGetter.getExtensions(AttachmentHandler.class)
var handlers = extensionComponentsFinder.getExtensions(AttachmentHandler.class);
return Flux.fromIterable(handlers)
.concatMap(handler -> handler.delete(deleteOption)) .concatMap(handler -> handler.delete(deleteOption))
.next(); .next());
});
} }
@Override @Override
public Mono<URI> getPermalink(Attachment attachment) { public Mono<URI> getPermalink(Attachment attachment) {
var handlers = extensionComponentsFinder.getExtensions(AttachmentHandler.class);
return client.get(Policy.class, attachment.getSpec().getPolicyName()) return client.get(Policy.class, attachment.getSpec().getPolicyName())
.flatMap(policy -> client.get(ConfigMap.class, policy.getSpec().getConfigMapName()) .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)) .concatMap(handler -> handler.getPermalink(attachment, policy, configMap))
.next())); .next()
)
);
} }
@Override @Override
public Mono<URI> getSharedURL(Attachment attachment, Duration ttl) { public Mono<URI> getSharedURL(Attachment attachment, Duration ttl) {
var handlers = extensionComponentsFinder.getExtensions(AttachmentHandler.class);
return client.get(Policy.class, attachment.getSpec().getPolicyName()) return client.get(Policy.class, attachment.getSpec().getPolicyName())
.flatMap(policy -> client.get(ConfigMap.class, policy.getSpec().getConfigMapName()) .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)) .concatMap(handler -> handler.getSharedURL(attachment, policy, configMap, ttl))
.next())); .next()
)
);
} }
private <T> Mono<T> authenticationConsumer(Function<Authentication, Mono<T>> func) { private <T> Mono<T> authenticationConsumer(Function<Authentication, Mono<T>> func) {

View File

@ -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 <T> extension component type
* @return extension components
*/
public <T> List<T> getExtensions(Class<T> type) {
assertExtensionPoint(type);
List<T> components = new ArrayList<>(pluginManager.getExtensions(type));
components.addAll(applicationContext.getBeansOfType(type).values());
return List.copyOf(components);
}
/**
* <p>Finds all extension components by plugin id.</p>
* If the plugin id is system or null, it means to find from halo.
*
* @param type subclass type of extension point
* @param <T> extension component type
* @return extension components
*/
public <T> List<T> getExtensions(Class<T> type, String pluginId) {
assertExtensionPoint(type);
List<T> 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");
}
}
}

View File

@ -1,16 +1,15 @@
package run.halo.app.theme.dialect; package run.halo.app.theme.dialect;
import java.util.Collection; import static org.thymeleaf.spring6.context.SpringContextUtils.getApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.thymeleaf.context.ITemplateContext; import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.model.IModel; import org.thymeleaf.model.IModel;
import org.thymeleaf.model.ITemplateEvent; import org.thymeleaf.model.ITemplateEvent;
import org.thymeleaf.processor.element.AbstractElementModelProcessor; import org.thymeleaf.processor.element.AbstractElementModelProcessor;
import org.thymeleaf.processor.element.IElementModelStructureHandler; import org.thymeleaf.processor.element.IElementModelStructureHandler;
import org.thymeleaf.spring6.context.SpringContextUtils;
import org.thymeleaf.templatemode.TemplateMode; 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. * Global head injection processor.
@ -71,13 +70,10 @@ public class GlobalHeadInjectionProcessor extends AbstractElementModelProcessor
modelToInsert.remove(0); modelToInsert.remove(0);
// apply processors to modelToInsert // apply processors to modelToInsert
Collection<TemplateHeadProcessor> templateHeadProcessors = getTemplateHeadProcessors(context)
getTemplateHeadProcessors(context); .concatMap(processor -> processor.process(context, modelToInsert, structureHandler))
.then()
for (TemplateHeadProcessor processor : templateHeadProcessors) {
processor.process(context, modelToInsert, structureHandler)
.block(); .block();
}
// reset model to insert // reset model to insert
model.reset(); model.reset();
@ -86,13 +82,12 @@ public class GlobalHeadInjectionProcessor extends AbstractElementModelProcessor
model.add(closeHeadTag); model.add(closeHeadTag);
} }
private Collection<TemplateHeadProcessor> getTemplateHeadProcessors(ITemplateContext context) { private Flux<TemplateHeadProcessor> getTemplateHeadProcessors(ITemplateContext context) {
ApplicationContext appCtx = SpringContextUtils.getApplicationContext(context); var extensionGetter = getApplicationContext(context).getBeanProvider(ExtensionGetter.class)
ExtensionComponentsFinder componentsFinder = .getIfUnique();
appCtx.getBean(ExtensionComponentsFinder.class); if (extensionGetter == null) {
return componentsFinder.getExtensions(TemplateHeadProcessor.class) return Flux.empty();
.stream() }
.sorted(AnnotationAwareOrderComparator.INSTANCE) return extensionGetter.getExtensions(TemplateHeadProcessor.class);
.toList();
} }
} }

View File

@ -18,6 +18,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import run.halo.app.content.NotificationReasonConst; import run.halo.app.content.NotificationReasonConst;
import run.halo.app.core.extension.User; 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.NotificationReasonEmitter;
import run.halo.app.notification.ReasonPayload; import run.halo.app.notification.ReasonPayload;
import run.halo.app.notification.UserIdentity; import run.halo.app.notification.UserIdentity;
import run.halo.app.plugin.ExtensionComponentsFinder; import run.halo.app.plugin.extensionpoint.ExtensionGetter;
/** /**
* Tests for {@link CommentNotificationReasonPublisher}. * Tests for {@link CommentNotificationReasonPublisher}.
@ -143,7 +144,7 @@ class CommentNotificationReasonPublisherTest {
NotificationReasonEmitter emitter; NotificationReasonEmitter emitter;
@Mock @Mock
ExtensionComponentsFinder extensionComponentsFinder; ExtensionGetter extensionGetter;
@Mock @Mock
ExternalLinkProcessor externalLinkProcessor; ExternalLinkProcessor externalLinkProcessor;
@ -248,9 +249,6 @@ class CommentNotificationReasonPublisherTest {
@Mock @Mock
NotificationReasonEmitter emitter; NotificationReasonEmitter emitter;
@Mock
ExtensionComponentsFinder extensionComponentsFinder;
@Mock @Mock
ExternalLinkProcessor externalLinkProcessor; ExternalLinkProcessor externalLinkProcessor;
@ -358,13 +356,15 @@ class CommentNotificationReasonPublisherTest {
NotificationReasonEmitter notificationReasonEmitter; NotificationReasonEmitter notificationReasonEmitter;
@Mock @Mock
ExtensionComponentsFinder extensionComponentsFinder; ExtensionGetter extensionGetter;
@InjectMocks @InjectMocks
CommentNotificationReasonPublisher.NewReplyReasonPublisher newReplyReasonPublisher; CommentNotificationReasonPublisher.NewReplyReasonPublisher newReplyReasonPublisher;
@Test @Test
void publishReasonByTest() { void publishReasonByTest() {
when(extensionGetter.getExtensions(CommentSubject.class))
.thenReturn(Flux.empty());
var reply = createReply("fake-reply"); var reply = createReply("fake-reply");
reply.getSpec().setQuoteReply("fake-quote-reply"); reply.getSpec().setQuoteReply("fake-quote-reply");

View File

@ -27,6 +27,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.test.StepVerifier; import reactor.test.StepVerifier;
import run.halo.app.content.TestPost; 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.infra.utils.JsonUtils;
import run.halo.app.metrics.CounterService; import run.halo.app.metrics.CounterService;
import run.halo.app.metrics.MeterUtils; 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; import run.halo.app.security.authorization.AuthorityUtils;
/** /**
@ -72,7 +73,7 @@ class CommentServiceImplTest {
private RoleService roleService; private RoleService roleService;
@Mock @Mock
private ExtensionComponentsFinder extensionComponentsFinder; private ExtensionGetter extensionGetter;
@InjectMocks @InjectMocks
private CommentServiceImpl commentService; private CommentServiceImpl commentService;
@ -101,8 +102,8 @@ class CommentServiceImplTest {
.thenReturn(Mono.just(false)); .thenReturn(Mono.just(false));
PostCommentSubject postCommentSubject = Mockito.mock(PostCommentSubject.class); PostCommentSubject postCommentSubject = Mockito.mock(PostCommentSubject.class);
when(extensionComponentsFinder.getExtensions(eq(CommentSubject.class))) when(extensionGetter.getExtensions(CommentSubject.class))
.thenReturn(List.of(postCommentSubject)); .thenReturn(Flux.just(postCommentSubject));
when(postCommentSubject.supports(any())).thenReturn(true); when(postCommentSubject.supports(any())).thenReturn(true);
when(postCommentSubject.get(eq("fake-post"))).thenReturn(Mono.just(post())); when(postCommentSubject.get(eq("fake-post"))).thenReturn(Mono.just(post()));

View File

@ -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.mockUser;
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity; import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.junit.jupiter.api.BeforeEach; 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.Metadata;
import run.halo.app.extension.PageRequest; import run.halo.app.extension.PageRequest;
import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.plugin.ExtensionComponentsFinder; import run.halo.app.plugin.extensionpoint.ExtensionGetter;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class AttachmentEndpointTest { class AttachmentEndpointTest {
@ -45,7 +44,7 @@ class AttachmentEndpointTest {
ReactiveExtensionClient client; ReactiveExtensionClient client;
@Mock @Mock
ExtensionComponentsFinder extensionComponentsFinder; ExtensionGetter extensionGetter;
AttachmentEndpoint endpoint; AttachmentEndpoint endpoint;
@ -53,7 +52,7 @@ class AttachmentEndpointTest {
@BeforeEach @BeforeEach
void setUp() { void setUp() {
var attachmentService = new DefaultAttachmentService(client, extensionComponentsFinder); var attachmentService = new DefaultAttachmentService(client, extensionGetter);
endpoint = new AttachmentEndpoint(attachmentService, client); endpoint = new AttachmentEndpoint(attachmentService, client);
webClient = WebTestClient.bindToRouterFunction(endpoint.endpoint()) webClient = WebTestClient.bindToRouterFunction(endpoint.endpoint())
.apply(springSecurity()) .apply(springSecurity())
@ -101,7 +100,7 @@ class AttachmentEndpointTest {
verify(client, never()).get(Policy.class, "fake-policy"); verify(client, never()).get(Policy.class, "fake-policy");
verify(client, never()).get(ConfigMap.class, "fake-configmap"); verify(client, never()).get(ConfigMap.class, "fake-configmap");
verify(client, never()).create(attachment); verify(client, never()).create(attachment);
verify(extensionComponentsFinder, never()).getExtensions(AttachmentHandler.class); verify(extensionGetter, never()).getExtensions(AttachmentHandler.class);
verify(handler, never()).upload(any()); verify(handler, never()).upload(any());
} }
@ -156,8 +155,8 @@ class AttachmentEndpointTest {
attachment.setMetadata(metadata); attachment.setMetadata(metadata);
when(handler.upload(any())).thenReturn(Mono.just(attachment)); when(handler.upload(any())).thenReturn(Mono.just(attachment));
when(extensionComponentsFinder.getExtensions(AttachmentHandler.class)).thenReturn( when(extensionGetter.getExtensions(AttachmentHandler.class))
List.of(handler)); .thenReturn(Flux.just(handler));
when(client.create(attachment)).thenReturn(Mono.just(attachment)); when(client.create(attachment)).thenReturn(Mono.just(attachment));
var builder = new MultipartBodyBuilder(); var builder = new MultipartBodyBuilder();
@ -195,8 +194,8 @@ class AttachmentEndpointTest {
attachment.setMetadata(metadata); attachment.setMetadata(metadata);
when(handler.upload(any())).thenReturn(Mono.just(attachment)); when(handler.upload(any())).thenReturn(Mono.just(attachment));
when(extensionComponentsFinder.getExtensions(AttachmentHandler.class)).thenReturn( when(extensionGetter.getExtensions(AttachmentHandler.class))
List.of(handler)); .thenReturn(Flux.just(handler));
when(client.create(attachment)).thenReturn(Mono.just(attachment)); when(client.create(attachment)).thenReturn(Mono.just(attachment));
var builder = new MultipartBodyBuilder(); var builder = new MultipartBodyBuilder();
@ -223,7 +222,6 @@ class AttachmentEndpointTest {
verify(client).get(Policy.class, "fake-policy"); verify(client).get(Policy.class, "fake-policy");
verify(client).get(ConfigMap.class, "fake-configmap"); verify(client).get(ConfigMap.class, "fake-configmap");
verify(client).create(attachment); verify(client).create(attachment);
verify(extensionComponentsFinder).getExtensions(AttachmentHandler.class);
verify(handler).upload(any()); verify(handler).upload(any());
} }
} }

View File

@ -29,7 +29,6 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
import run.halo.app.infra.SystemSetting; import run.halo.app.infra.SystemSetting;
import run.halo.app.plugin.ExtensionComponentsFinder;
import run.halo.app.plugin.extensionpoint.ExtensionGetter; import run.halo.app.plugin.extensionpoint.ExtensionGetter;
/** /**

View File

@ -3,6 +3,7 @@ package run.halo.app.theme.dialect;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.util.ArrayList; import java.util.ArrayList;
@ -16,7 +17,9 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.thymeleaf.IEngineConfiguration; import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.TemplateEngine; import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context; import org.thymeleaf.context.Context;
@ -25,12 +28,13 @@ import org.thymeleaf.spring6.expression.ThymeleafEvaluationContext;
import org.thymeleaf.templateresolver.StringTemplateResolver; import org.thymeleaf.templateresolver.StringTemplateResolver;
import org.thymeleaf.templateresource.ITemplateResource; import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.templateresource.StringTemplateResource; import org.thymeleaf.templateresource.StringTemplateResource;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import run.halo.app.core.extension.content.Post; import run.halo.app.core.extension.content.Post;
import run.halo.app.extension.Metadata; import run.halo.app.extension.Metadata;
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
import run.halo.app.infra.SystemSetting; 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.DefaultTemplateEnum;
import run.halo.app.theme.finders.PostFinder; import run.halo.app.theme.finders.PostFinder;
import run.halo.app.theme.finders.SinglePageFinder; import run.halo.app.theme.finders.SinglePageFinder;
@ -64,7 +68,7 @@ class ContentTemplateHeadProcessorIntegrationTest {
private SystemConfigurableEnvironmentFetcher fetcher; private SystemConfigurableEnvironmentFetcher fetcher;
@Mock @Mock
private ExtensionComponentsFinder extensionComponentsFinder; ExtensionGetter extensionGetter;
private TemplateEngine templateEngine; private TemplateEngine templateEngine;
@ -98,17 +102,18 @@ class ContentTemplateHeadProcessorIntegrationTest {
lenient().when(fetcher.fetch(eq(SystemSetting.CodeInjection.GROUP), lenient().when(fetcher.fetch(eq(SystemSetting.CodeInjection.GROUP),
eq(SystemSetting.CodeInjection.class))).thenReturn(Mono.just(codeInjection)); 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))) lenient().when(fetcher.fetch(eq(SystemSetting.Seo.GROUP), eq(SystemSetting.Seo.class)))
.thenReturn(Mono.empty()); .thenReturn(Mono.empty());
lenient().when(applicationContext.getBean(eq(ExtensionComponentsFinder.class))) lenient().when(applicationContext.getBeanProvider(ExtensionGetter.class))
.thenReturn(extensionComponentsFinder); .thenAnswer(invocation -> {
var objectProvider = mock(ObjectProvider.class);
lenient().when(extensionComponentsFinder.getExtensions(eq(TemplateHeadProcessor.class))) when(objectProvider.getIfUnique()).thenReturn(extensionGetter);
.thenReturn(new ArrayList<>(map.values())); return objectProvider;
});
lenient().when(extensionGetter.getExtensions(TemplateHeadProcessor.class)).thenReturn(
Flux.fromIterable(map.values()).sort(AnnotationAwareOrderComparator.INSTANCE)
);
lenient().when(applicationContext.getBean(eq(SystemConfigurableEnvironmentFetcher.class))) lenient().when(applicationContext.getBean(eq(SystemConfigurableEnvironmentFetcher.class)))
.thenReturn(fetcher); .thenReturn(fetcher);
lenient().when(fetcher.fetchComment()).thenReturn(Mono.just(new SystemSetting.Comment())); lenient().when(fetcher.fetchComment()).thenReturn(Mono.just(new SystemSetting.Comment()));

View File

@ -3,6 +3,7 @@ package run.halo.app.theme.dialect;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableSortedMap; 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.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.thymeleaf.IEngineConfiguration; import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.TemplateEngine; import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context; import org.thymeleaf.context.Context;
@ -26,13 +29,16 @@ import org.thymeleaf.spring6.expression.ThymeleafEvaluationContext;
import org.thymeleaf.templateresolver.StringTemplateResolver; import org.thymeleaf.templateresolver.StringTemplateResolver;
import org.thymeleaf.templateresource.ITemplateResource; import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.templateresource.StringTemplateResource; import org.thymeleaf.templateresource.StringTemplateResource;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import run.halo.app.core.extension.User; import run.halo.app.core.extension.User;
import run.halo.app.core.extension.content.Post; import run.halo.app.core.extension.content.Post;
import run.halo.app.extension.Metadata; import run.halo.app.extension.Metadata;
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
import run.halo.app.infra.SystemSetting; 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.DefaultTemplateEnum;
import run.halo.app.theme.finders.PostFinder; import run.halo.app.theme.finders.PostFinder;
import run.halo.app.theme.finders.SinglePageFinder; import run.halo.app.theme.finders.SinglePageFinder;
@ -67,7 +73,7 @@ class HaloProcessorDialectTest {
private SystemConfigurableEnvironmentFetcher fetcher; private SystemConfigurableEnvironmentFetcher fetcher;
@Mock @Mock
private ExtensionComponentsFinder extensionComponentsFinder; ExtensionGetter extensionGetter;
private TemplateEngine templateEngine; private TemplateEngine templateEngine;
@ -84,29 +90,30 @@ class HaloProcessorDialectTest {
map.put("templateGlobalHeadProcessor", new TemplateGlobalHeadProcessor(fetcher)); map.put("templateGlobalHeadProcessor", new TemplateGlobalHeadProcessor(fetcher));
map.put("faviconHeadProcessor", new DefaultFaviconHeadProcessor(fetcher)); map.put("faviconHeadProcessor", new DefaultFaviconHeadProcessor(fetcher));
map.put("globalSeoProcessor", new GlobalSeoProcessor(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("<meta name=\"content-head-test\" content=\"test\" />"); codeInjection.setContentHead("<meta name=\"content-head-test\" content=\"test\" />");
codeInjection.setGlobalHead("<meta name=\"global-head-test\" content=\"test\" />"); codeInjection.setGlobalHead("<meta name=\"global-head-test\" content=\"test\" />");
codeInjection.setFooter("<footer>hello this is global footer.</footer>"); codeInjection.setFooter("<footer>hello this is global footer.</footer>");
lenient().when(fetcher.fetch(eq(SystemSetting.CodeInjection.GROUP), lenient().when(fetcher.fetch(eq(CodeInjection.GROUP), eq(CodeInjection.class)))
eq(SystemSetting.CodeInjection.class))).thenReturn(Mono.just(codeInjection)); .thenReturn(Mono.just(codeInjection));
lenient().when(applicationContext.getBean(eq(SystemConfigurableEnvironmentFetcher.class))) lenient().when(applicationContext.getBean(eq(SystemConfigurableEnvironmentFetcher.class)))
.thenReturn(fetcher); .thenReturn(fetcher);
lenient().when(fetcher.fetch(eq(SystemSetting.Seo.GROUP), lenient().when(fetcher.fetch(eq(Seo.GROUP), eq(Seo.class)))
eq(SystemSetting.Seo.class))).thenReturn(Mono.empty()); .thenReturn(Mono.empty());
lenient().when(applicationContext.getBean(eq(ExtensionComponentsFinder.class))) lenient().when(applicationContext.getBeanProvider(ExtensionGetter.class))
.thenReturn(extensionComponentsFinder); .then(invocation -> {
@SuppressWarnings("unchecked")
ObjectProvider<ExtensionGetter> 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()) lenient().when(fetcher.fetchComment())
.thenReturn(Mono.just(new SystemSetting.Comment())); .thenReturn(Mono.just(new SystemSetting.Comment()));
} }
@ -192,10 +199,10 @@ class HaloProcessorDialectTest {
@Test @Test
void blockSeo() { void blockSeo() {
final Context context = getContext(); final Context context = getContext();
SystemSetting.Seo seo = new SystemSetting.Seo(); Seo seo = new Seo();
seo.setBlockSpiders(true); seo.setBlockSpiders(true);
when(fetcher.fetch(eq(SystemSetting.Seo.GROUP), when(fetcher.fetch(eq(Seo.GROUP),
eq(SystemSetting.Seo.class))).thenReturn(Mono.just(seo)); eq(Seo.class))).thenReturn(Mono.just(seo));
SystemSetting.Basic basic = new SystemSetting.Basic(); SystemSetting.Basic basic = new SystemSetting.Basic();
basic.setFavicon("favicon.ico"); basic.setFavicon("favicon.ico");
when(fetcher.fetch(eq(SystemSetting.Basic.GROUP), when(fetcher.fetch(eq(SystemSetting.Basic.GROUP),
@ -222,11 +229,11 @@ class HaloProcessorDialectTest {
@Test @Test
void seoWithKeywordsAndDescription() { void seoWithKeywordsAndDescription() {
final Context context = getContext(); final Context context = getContext();
SystemSetting.Seo seo = new SystemSetting.Seo(); Seo seo = new Seo();
seo.setKeywords("K1, K2, K3"); seo.setKeywords("K1, K2, K3");
seo.setDescription("This is a description."); seo.setDescription("This is a description.");
when(fetcher.fetch(eq(SystemSetting.Seo.GROUP), when(fetcher.fetch(eq(Seo.GROUP),
eq(SystemSetting.Seo.class))).thenReturn(Mono.just(seo)); eq(Seo.class))).thenReturn(Mono.just(seo));
SystemSetting.Basic basic = new SystemSetting.Basic(); SystemSetting.Basic basic = new SystemSetting.Basic();
basic.setFavicon("favicon.ico"); basic.setFavicon("favicon.ico");
when(fetcher.fetch(eq(SystemSetting.Basic.GROUP), when(fetcher.fetch(eq(SystemSetting.Basic.GROUP),