mirror of https://github.com/halo-dev/halo
refactor: optimize the usage of comment widget extension point (#4249)
#### What type of PR is this? /kind improvement /area core /milestone 2.8.x #### What this PR does / why we need it: 优化评论扩展点的使用方式 how to test it? 测试评论插件是否正常可用 #### Does this PR introduce a user-facing change? ```release-note 优化评论扩展点的使用方式 ```pull/4270/head
parent
5eb9b68209
commit
133e54106d
|
@ -1,11 +1,14 @@
|
|||
package run.halo.app.plugin.extensionpoint;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.pf4j.ExtensionPoint;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
@ -32,14 +35,17 @@ public class DefaultExtensionGetter implements ExtensionGetter {
|
|||
.switchIfEmpty(Mono.just(ExtensionPointEnabled.EMPTY))
|
||||
.mapNotNull(enabled -> {
|
||||
var implClassNames = enabled.getOrDefault(extensionPoint.getName(), Set.of());
|
||||
return pluginManager.getExtensions(extensionPoint)
|
||||
List<T> allExtensions = getAllExtensions(extensionPoint);
|
||||
if (allExtensions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return allExtensions
|
||||
.stream()
|
||||
.filter(impl -> implClassNames.contains(impl.getClass().getName()))
|
||||
.findFirst()
|
||||
// Fallback to local implementation of the extension point.
|
||||
// This will happen when no proper configuration is found.
|
||||
.orElseGet(() ->
|
||||
applicationContext.getBeanProvider(extensionPoint).getIfAvailable());
|
||||
.orElseGet(() -> allExtensions.get(0));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -74,16 +80,23 @@ public class DefaultExtensionGetter implements ExtensionGetter {
|
|||
if (type == ExtensionPointDefinition.ExtensionPointType.SINGLETON) {
|
||||
return getEnabledExtension(extensionPoint).flux();
|
||||
}
|
||||
Stream<T> pluginExtsStream = pluginManager.getExtensions(extensionPoint)
|
||||
.stream();
|
||||
Stream<T> systemExtsStream = applicationContext.getBeanProvider(extensionPoint)
|
||||
.orderedStream();
|
||||
|
||||
// TODO If the type is sortable, may need to process the returned order.
|
||||
return Flux.just(pluginExtsStream, systemExtsStream)
|
||||
.flatMap(Flux::fromStream);
|
||||
return Flux.fromIterable(getAllExtensions(extensionPoint));
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
<T extends ExtensionPoint> List<T> getAllExtensions(Class<T> extensionPoint) {
|
||||
Stream<T> pluginExtsStream = pluginManager.getExtensions(extensionPoint)
|
||||
.stream();
|
||||
Stream<T> systemExtsStream = applicationContext.getBeanProvider(extensionPoint)
|
||||
.orderedStream();
|
||||
return Stream.concat(systemExtsStream, pluginExtsStream)
|
||||
.sorted(new AnnotationAwareOrderComparator())
|
||||
.toList();
|
||||
}
|
||||
|
||||
Mono<ExtensionPointDefinition> fetchExtensionPointDefinition(
|
||||
Class<? extends ExtensionPoint> extensionPoint) {
|
||||
// TODO Optimize query
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package run.halo.app.theme.dialect;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.thymeleaf.context.ITemplateContext;
|
||||
import org.thymeleaf.model.IProcessableElementTag;
|
||||
|
@ -8,7 +7,7 @@ import org.thymeleaf.processor.element.AbstractElementTagProcessor;
|
|||
import org.thymeleaf.processor.element.IElementTagStructureHandler;
|
||||
import org.thymeleaf.spring6.context.SpringContextUtils;
|
||||
import org.thymeleaf.templatemode.TemplateMode;
|
||||
import run.halo.app.plugin.ExtensionComponentsFinder;
|
||||
import run.halo.app.plugin.extensionpoint.ExtensionGetter;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -44,15 +43,15 @@ public class CommentElementTagProcessor extends AbstractElementTagProcessor {
|
|||
protected void doProcess(ITemplateContext context, IProcessableElementTag tag,
|
||||
IElementTagStructureHandler structureHandler) {
|
||||
final ApplicationContext appCtx = SpringContextUtils.getApplicationContext(context);
|
||||
ExtensionComponentsFinder componentsFinder =
|
||||
appCtx.getBean(ExtensionComponentsFinder.class);
|
||||
List<CommentWidget> commentWidgets = componentsFinder.getExtensions(CommentWidget.class);
|
||||
if (commentWidgets.isEmpty()) {
|
||||
ExtensionGetter extensionGetter = appCtx.getBean(ExtensionGetter.class);
|
||||
CommentWidget commentWidget =
|
||||
extensionGetter.getEnabledExtensionByDefinition(CommentWidget.class)
|
||||
.next()
|
||||
.block();
|
||||
if (commentWidget == null) {
|
||||
structureHandler.replaceWith("", false);
|
||||
return;
|
||||
}
|
||||
// TODO if find more than one comment widget, query CommentWidget setting to decide which
|
||||
// one to use.
|
||||
commentWidgets.get(0).render(context, tag, structureHandler);
|
||||
commentWidget.render(context, tag, structureHandler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ spec:
|
|||
className: run.halo.app.theme.ReactivePostContentHandler
|
||||
displayName: ReactivePostContentHandler
|
||||
type: MULTI_INSTANCE
|
||||
description: "Provides a way to extend the post content to be displayed in the theme-side."
|
||||
description: "Provides a way to extend the post content to be displayed on the theme-side."
|
||||
|
||||
---
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
|
@ -29,4 +29,15 @@ spec:
|
|||
className: run.halo.app.theme.ReactiveSinglePageContentHandler
|
||||
displayName: ReactiveSinglePageContentHandler
|
||||
type: MULTI_INSTANCE
|
||||
description: "Provides a way to extend the single page content to be displayed in the theme-side."
|
||||
description: "Provides a way to extend the single page content to be displayed on the theme-side."
|
||||
|
||||
---
|
||||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: ExtensionPointDefinition
|
||||
metadata:
|
||||
name: comment-widget
|
||||
spec:
|
||||
className: run.halo.app.theme.dialect.CommentWidget
|
||||
displayName: CommentWidget
|
||||
type: SINGLETON
|
||||
description: "Provides an extension point for the comment widget on the theme-side."
|
||||
|
|
|
@ -4,7 +4,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -24,7 +23,9 @@ 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 run.halo.app.plugin.ExtensionComponentsFinder;
|
||||
import run.halo.app.plugin.extensionpoint.ExtensionGetter;
|
||||
|
||||
/**
|
||||
* Tests for {@link CommentElementTagProcessor}.
|
||||
|
@ -41,7 +42,7 @@ class CommentElementTagProcessorTest {
|
|||
private ApplicationContext applicationContext;
|
||||
|
||||
@Mock
|
||||
private ExtensionComponentsFinder componentsFinder;
|
||||
private ExtensionGetter extensionGetter;
|
||||
|
||||
private TemplateEngine templateEngine;
|
||||
|
||||
|
@ -51,14 +52,16 @@ class CommentElementTagProcessorTest {
|
|||
templateEngine = new TemplateEngine();
|
||||
templateEngine.setDialects(Set.of(haloProcessorDialect, new SpringStandardDialect()));
|
||||
templateEngine.addTemplateResolver(new TestTemplateResolver());
|
||||
when(applicationContext.getBean(eq(ExtensionComponentsFinder.class)))
|
||||
.thenReturn(componentsFinder);
|
||||
when(applicationContext.getBean(eq(ExtensionGetter.class)))
|
||||
.thenReturn(extensionGetter);
|
||||
}
|
||||
|
||||
@Test
|
||||
void doProcess() {
|
||||
Context context = getContext();
|
||||
|
||||
when(extensionGetter.getEnabledExtensionByDefinition(eq(CommentWidget.class)))
|
||||
.thenReturn(Flux.empty());
|
||||
String result = templateEngine.process("commentWidget", context);
|
||||
assertThat(result).isEqualTo("""
|
||||
<!DOCTYPE html>
|
||||
|
@ -70,8 +73,8 @@ class CommentElementTagProcessorTest {
|
|||
</html>
|
||||
""");
|
||||
|
||||
when(componentsFinder.getExtensions(CommentWidget.class))
|
||||
.thenReturn(List.of(new DefaultCommentWidget()));
|
||||
when(extensionGetter.getEnabledExtensionByDefinition(eq(CommentWidget.class)))
|
||||
.thenReturn(Flux.just(new DefaultCommentWidget()));
|
||||
result = templateEngine.process("commentWidget", context);
|
||||
assertThat(result).isEqualTo("""
|
||||
<!DOCTYPE html>
|
||||
|
|
Loading…
Reference in New Issue