From 0df7857ef8d16867dabd3fc790034b10ec867ad3 Mon Sep 17 00:00:00 2001 From: John Niang Date: Fri, 25 Nov 2022 19:13:09 +0800 Subject: [PATCH] Refactor reconcilers registration (#2737) #### What type of PR is this? /kind cleanup /kind improvement /area core /milestone 2.0.0 #### What this PR does / why we need it: This PR mainly refactors registration of reconcilers to register reconciler more convinient. After that, it is possible to reigster and start reconciler in plugin. #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/2305 #### Does this PR introduce a user-facing change? ```release-note None ``` --- .../app/config/ExtensionConfiguration.java | 193 +----------------- .../reconciler/CategoryReconciler.java | 11 + .../reconciler/CommentReconciler.java | 11 + .../reconciler/MenuItemReconciler.java | 11 + .../extension/reconciler/MenuReconciler.java | 19 -- .../reconciler/PluginReconciler.java | 11 + .../extension/reconciler/PostReconciler.java | 13 ++ .../reconciler/ReverseProxyReconciler.java | 11 + .../reconciler/RoleBindingReconciler.java | 11 + .../extension/reconciler/RoleReconciler.java | 11 + .../reconciler/SinglePageReconciler.java | 11 + .../reconciler/SystemSettingReconciler.java | 11 + .../extension/reconciler/TagReconciler.java | 11 + .../extension/reconciler/ThemeReconciler.java | 11 + .../extension/reconciler/UserReconciler.java | 12 ++ .../attachment/AttachmentReconciler.java | 11 + .../controller/ControllerBuilder.java | 12 +- .../controller/ControllerManager.java | 49 ++--- .../controller/DefaultControllerManager.java | 83 ++++++++ .../app/extension/controller/Reconciler.java | 2 + .../gc/GarbageCollectorConfiguration.java | 36 ---- .../extension/gc/GcControllerInitializer.java | 28 +++ .../halo/app/extension/gc/GcReconciler.java | 29 ++- .../controller/ControllerBuilderTest.java | 31 +-- 24 files changed, 337 insertions(+), 302 deletions(-) delete mode 100644 src/main/java/run/halo/app/core/extension/reconciler/MenuReconciler.java create mode 100644 src/main/java/run/halo/app/extension/controller/DefaultControllerManager.java delete mode 100644 src/main/java/run/halo/app/extension/gc/GarbageCollectorConfiguration.java create mode 100644 src/main/java/run/halo/app/extension/gc/GcControllerInitializer.java diff --git a/src/main/java/run/halo/app/config/ExtensionConfiguration.java b/src/main/java/run/halo/app/config/ExtensionConfiguration.java index 859ef4cf2..5eb0c2e9e 100644 --- a/src/main/java/run/halo/app/config/ExtensionConfiguration.java +++ b/src/main/java/run/halo/app/config/ExtensionConfiguration.java @@ -1,65 +1,18 @@ package run.halo.app.config; -import io.micrometer.core.instrument.MeterRegistry; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; -import run.halo.app.content.ContentService; -import run.halo.app.content.PostService; -import run.halo.app.content.permalinks.CategoryPermalinkPolicy; -import run.halo.app.content.permalinks.PostPermalinkPolicy; -import run.halo.app.content.permalinks.TagPermalinkPolicy; -import run.halo.app.core.extension.Category; -import run.halo.app.core.extension.Comment; -import run.halo.app.core.extension.Menu; -import run.halo.app.core.extension.MenuItem; -import run.halo.app.core.extension.Plugin; -import run.halo.app.core.extension.Post; -import run.halo.app.core.extension.ReverseProxy; -import run.halo.app.core.extension.Role; -import run.halo.app.core.extension.RoleBinding; -import run.halo.app.core.extension.SinglePage; -import run.halo.app.core.extension.Tag; -import run.halo.app.core.extension.Theme; -import run.halo.app.core.extension.User; -import run.halo.app.core.extension.attachment.Attachment; -import run.halo.app.core.extension.reconciler.CategoryReconciler; -import run.halo.app.core.extension.reconciler.CommentReconciler; -import run.halo.app.core.extension.reconciler.MenuItemReconciler; -import run.halo.app.core.extension.reconciler.MenuReconciler; -import run.halo.app.core.extension.reconciler.PluginReconciler; -import run.halo.app.core.extension.reconciler.PostReconciler; -import run.halo.app.core.extension.reconciler.ReverseProxyReconciler; -import run.halo.app.core.extension.reconciler.RoleBindingReconciler; -import run.halo.app.core.extension.reconciler.RoleReconciler; -import run.halo.app.core.extension.reconciler.SinglePageReconciler; -import run.halo.app.core.extension.reconciler.SystemSettingReconciler; -import run.halo.app.core.extension.reconciler.TagReconciler; -import run.halo.app.core.extension.reconciler.ThemeReconciler; -import run.halo.app.core.extension.reconciler.UserReconciler; -import run.halo.app.core.extension.reconciler.attachment.AttachmentReconciler; -import run.halo.app.core.extension.service.RoleService; -import run.halo.app.extension.ConfigMap; import run.halo.app.extension.DefaultSchemeManager; import run.halo.app.extension.DefaultSchemeWatcherManager; import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.extension.SchemeManager; import run.halo.app.extension.SchemeWatcherManager; -import run.halo.app.extension.controller.Controller; -import run.halo.app.extension.controller.ControllerBuilder; -import run.halo.app.extension.controller.ControllerManager; +import run.halo.app.extension.controller.DefaultControllerManager; import run.halo.app.extension.router.ExtensionCompositeRouterFunction; -import run.halo.app.infra.ExternalUrlSupplier; -import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; -import run.halo.app.infra.properties.HaloProperties; -import run.halo.app.metrics.CounterService; -import run.halo.app.plugin.ExtensionComponentsFinder; -import run.halo.app.plugin.HaloPluginManager; -import run.halo.app.plugin.resources.ReverseProxyRouterFunctionRegistry; @Configuration(proxyBeanMethods = false) public class ExtensionConfiguration { @@ -87,150 +40,10 @@ public class ExtensionConfiguration { static class ExtensionControllerConfiguration { @Bean - ControllerManager controllerManager() { - return new ControllerManager(); + DefaultControllerManager controllerManager(ExtensionClient client) { + return new DefaultControllerManager(client); } - @Bean - Controller userController(ExtensionClient client) { - return new ControllerBuilder("user", client) - .reconciler(new UserReconciler(client)) - .extension(new User()) - .build(); - } - - @Bean - Controller roleController(ExtensionClient client, RoleService roleService) { - return new ControllerBuilder("role", client) - .reconciler(new RoleReconciler(client, roleService)) - .extension(new Role()) - .build(); - } - - @Bean - Controller roleBindingController(ExtensionClient client) { - return new ControllerBuilder("role-binding", client) - .reconciler(new RoleBindingReconciler(client)) - .extension(new RoleBinding()) - .build(); - } - - @Bean - Controller pluginController(ExtensionClient client, HaloPluginManager haloPluginManager) { - return new ControllerBuilder("plugin", client) - .reconciler(new PluginReconciler(client, haloPluginManager)) - .extension(new Plugin()) - .build(); - } - - @Bean - Controller menuController(ExtensionClient client) { - return new ControllerBuilder("menu", client) - .reconciler(new MenuReconciler(client)) - .extension(new Menu()) - .build(); - } - - @Bean - Controller menuItemController(ExtensionClient client) { - return new ControllerBuilder("menu-item", client) - .reconciler(new MenuItemReconciler(client)) - .extension(new MenuItem()) - .build(); - } - - @Bean - Controller themeController(ExtensionClient client, HaloProperties haloProperties) { - return new ControllerBuilder("theme", client) - .reconciler(new ThemeReconciler(client, haloProperties)) - .extension(new Theme()) - .build(); - } - - @Bean - Controller postController(ExtensionClient client, ContentService contentService, - PostPermalinkPolicy postPermalinkPolicy, CounterService counterService, - PostService postService, ApplicationContext applicationContext) { - return new ControllerBuilder("post", client) - .reconciler(new PostReconciler(client, contentService, postService, - postPermalinkPolicy, - counterService, applicationContext)) - .extension(new Post()) - // TODO Make it configurable - .workerCount(10) - .build(); - } - - @Bean - Controller categoryController(ExtensionClient client, - CategoryPermalinkPolicy categoryPermalinkPolicy) { - return new ControllerBuilder("category", client) - .reconciler(new CategoryReconciler(client, categoryPermalinkPolicy)) - .extension(new Category()) - .build(); - } - - @Bean - Controller tagController(ExtensionClient client, TagPermalinkPolicy tagPermalinkPolicy) { - return new ControllerBuilder("tag", client) - .reconciler(new TagReconciler(client, tagPermalinkPolicy)) - .extension(new Tag()) - .build(); - } - - @Bean - Controller systemSettingController(ExtensionClient client, - SystemConfigurableEnvironmentFetcher environmentFetcher, - ApplicationContext applicationContext) { - return new ControllerBuilder("system-setting", client) - .reconciler(new SystemSettingReconciler(client, environmentFetcher, - applicationContext)) - .extension(new ConfigMap()) - .build(); - } - - @Bean - Controller attachmentController(ExtensionClient client, - ExtensionComponentsFinder extensionComponentsFinder, - ExternalUrlSupplier externalUrl) { - return new ControllerBuilder("attachment", client) - .reconciler( - new AttachmentReconciler(client, extensionComponentsFinder, externalUrl)) - .extension(new Attachment()) - .build(); - } - - @Bean - Controller singlePageController(ExtensionClient client, ContentService contentService, - ApplicationContext applicationContext, CounterService counterService, - ExternalUrlSupplier externalUrlSupplier) { - return new ControllerBuilder("single-page", client) - .reconciler(new SinglePageReconciler(client, contentService, - applicationContext, counterService, externalUrlSupplier) - ) - .extension(new SinglePage()) - .build(); - } - - @Bean - Controller commentController(ExtensionClient client, MeterRegistry meterRegistry, - SchemeManager schemeManager) { - return new ControllerBuilder("comment", client) - // TODO Make it configurable - .workerCount(10) - .reconciler(new CommentReconciler(client, meterRegistry, schemeManager)) - .extension(new Comment()) - .build(); - } - - @Bean - Controller reverseProxyController(ExtensionClient client, - ReverseProxyRouterFunctionRegistry reverseProxyRouterFunctionRegistry) { - return new ControllerBuilder("reverse-proxy", client) - .reconciler(new ReverseProxyReconciler(client, reverseProxyRouterFunctionRegistry)) - .extension(new ReverseProxy()) - .build(); - } } } diff --git a/src/main/java/run/halo/app/core/extension/reconciler/CategoryReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/CategoryReconciler.java index ee71ae9cb..72f7497e3 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/CategoryReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/CategoryReconciler.java @@ -12,10 +12,13 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; import run.halo.app.content.permalinks.CategoryPermalinkPolicy; import run.halo.app.core.extension.Category; import run.halo.app.core.extension.Post; import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.infra.utils.JsonUtils; @@ -25,6 +28,7 @@ import run.halo.app.infra.utils.JsonUtils; * @author guqing * @since 2.0.0 */ +@Component public class CategoryReconciler implements Reconciler { private static final String FINALIZER_NAME = "category-protection"; private final ExtensionClient client; @@ -54,6 +58,13 @@ public class CategoryReconciler implements Reconciler { .orElseGet(() -> new Result(false, null)); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new Category()) + .build(); + } + private void addFinalizerIfNecessary(Category oldCategory) { Set finalizers = oldCategory.getMetadata().getFinalizers(); if (finalizers != null && finalizers.contains(FINALIZER_NAME)) { diff --git a/src/main/java/run/halo/app/core/extension/reconciler/CommentReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/CommentReconciler.java index 735a128a9..14f8b69f1 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/CommentReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/CommentReconciler.java @@ -13,12 +13,15 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; import run.halo.app.core.extension.Comment; import run.halo.app.core.extension.Reply; import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.GroupVersionKind; import run.halo.app.extension.Ref; import run.halo.app.extension.SchemeManager; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.infra.utils.JsonUtils; import run.halo.app.metrics.MeterUtils; @@ -29,6 +32,7 @@ import run.halo.app.metrics.MeterUtils; * @author guqing * @since 2.0.0 */ +@Component public class CommentReconciler implements Reconciler { public static final String FINALIZER_NAME = "comment-protection"; private final ExtensionClient client; @@ -58,6 +62,13 @@ public class CommentReconciler implements Reconciler { .orElseGet(() -> new Result(false, null)); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new Comment()) + .build(); + } + private boolean isDeleted(Comment comment) { return comment.getMetadata().getDeletionTimestamp() != null; } diff --git a/src/main/java/run/halo/app/core/extension/reconciler/MenuItemReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/MenuItemReconciler.java index 26e3f75bc..7aac808dd 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/MenuItemReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/MenuItemReconciler.java @@ -2,6 +2,7 @@ package run.halo.app.core.extension.reconciler; import java.time.Duration; import java.util.Objects; +import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import run.halo.app.core.extension.Category; import run.halo.app.core.extension.MenuItem; @@ -12,9 +13,12 @@ import run.halo.app.core.extension.SinglePage; import run.halo.app.core.extension.Tag; import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.Ref; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.controller.Reconciler.Request; +@Component public class MenuItemReconciler implements Reconciler { private final ExtensionClient client; @@ -46,6 +50,13 @@ public class MenuItemReconciler implements Reconciler { }).orElseGet(() -> new Result(false, null)); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new MenuItem()) + .build(); + } + private Result handleCategoryRef(String menuItemName, MenuItemStatus status, Ref categoryRef) { client.fetch(Category.class, categoryRef.getName()) .filter(category -> category.getStatus() != null) diff --git a/src/main/java/run/halo/app/core/extension/reconciler/MenuReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/MenuReconciler.java deleted file mode 100644 index f83b4f2ff..000000000 --- a/src/main/java/run/halo/app/core/extension/reconciler/MenuReconciler.java +++ /dev/null @@ -1,19 +0,0 @@ -package run.halo.app.core.extension.reconciler; - -import run.halo.app.extension.ExtensionClient; -import run.halo.app.extension.controller.Reconciler; - -public class MenuReconciler implements Reconciler { - - private final ExtensionClient client; - - public MenuReconciler(ExtensionClient client) { - this.client = client; - } - - @Override - public Result reconcile(Request request) { - return new Result(false, null); - } - -} diff --git a/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java index 5e44e49c8..1314ebb17 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java @@ -17,10 +17,13 @@ import org.pf4j.PluginRuntimeException; import org.pf4j.PluginState; import org.pf4j.PluginWrapper; import org.pf4j.RuntimeMode; +import org.springframework.stereotype.Component; import run.halo.app.core.extension.Plugin; import run.halo.app.core.extension.ReverseProxy; import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.Metadata; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.controller.Reconciler.Request; import run.halo.app.infra.utils.JsonUtils; @@ -37,6 +40,7 @@ import run.halo.app.plugin.resources.BundleResourceUtils; * @since 2.0.0 */ @Slf4j +@Component public class PluginReconciler implements Reconciler { private static final String FINALIZER_NAME = "plugin-protection"; private final ExtensionClient client; @@ -63,6 +67,13 @@ public class PluginReconciler implements Reconciler { return new Result(false, null); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new Plugin()) + .build(); + } + private void reconcilePluginState(String name) { if (haloPluginManager.getPlugin(name) == null) { ensurePluginLoaded(); diff --git a/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java index 595552bfe..ebe733c31 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java @@ -10,6 +10,7 @@ import lombok.AllArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.jsoup.Jsoup; import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; import org.springframework.util.Assert; import run.halo.app.content.ContentService; import run.halo.app.content.PostService; @@ -23,6 +24,8 @@ import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.ExtensionOperator; import run.halo.app.extension.ExtensionUtil; import run.halo.app.extension.Ref; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.infra.Condition; import run.halo.app.infra.ConditionList; @@ -45,6 +48,7 @@ import run.halo.app.metrics.MeterUtils; * @since 2.0.0 */ @AllArgsConstructor +@Component public class PostReconciler implements Reconciler { private static final String FINALIZER_NAME = "post-protection"; private final ExtensionClient client; @@ -73,6 +77,15 @@ public class PostReconciler implements Reconciler { return new Result(false, null); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new Post()) + // TODO Make it configurable + .workerCount(10) + .build(); + } + private void reconcileSpec(String name) { client.fetch(Post.class, name).ifPresent(post -> { // un-publish post if necessary diff --git a/src/main/java/run/halo/app/core/extension/reconciler/ReverseProxyReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/ReverseProxyReconciler.java index ef397a559..7b625fad3 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/ReverseProxyReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/ReverseProxyReconciler.java @@ -4,8 +4,11 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; import run.halo.app.core.extension.ReverseProxy; import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.plugin.PluginConst; import run.halo.app.plugin.resources.ReverseProxyRouterFunctionRegistry; @@ -16,6 +19,7 @@ import run.halo.app.plugin.resources.ReverseProxyRouterFunctionRegistry; * @author guqing * @since 2.0.0 */ +@Component public class ReverseProxyReconciler implements Reconciler { private static final String FINALIZER_NAME = "reverse-proxy-protection"; private final ExtensionClient client; @@ -42,6 +46,13 @@ public class ReverseProxyReconciler implements Reconciler { .orElse(new Result(false, null)); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new ReverseProxy()) + .build(); + } + private void registerReverseProxy(ReverseProxy reverseProxy) { String pluginId = getPluginId(reverseProxy); routerFunctionRegistry.register(pluginId, reverseProxy).block(); diff --git a/src/main/java/run/halo/app/core/extension/reconciler/RoleBindingReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/RoleBindingReconciler.java index 2b6eaec0f..427fdbec4 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/RoleBindingReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/RoleBindingReconciler.java @@ -9,16 +9,20 @@ import java.util.Objects; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.data.util.Lazy; +import org.springframework.stereotype.Component; import run.halo.app.core.extension.Role; import run.halo.app.core.extension.RoleBinding; import run.halo.app.core.extension.RoleBinding.Subject; import run.halo.app.core.extension.User; import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.controller.Reconciler.Request; import run.halo.app.infra.utils.JsonUtils; @Slf4j +@Component public class RoleBindingReconciler implements Reconciler { private final ExtensionClient client; @@ -68,4 +72,11 @@ public class RoleBindingReconciler implements Reconciler { return new Result(false, null); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new RoleBinding()) + .build(); + } + } diff --git a/src/main/java/run/halo/app/core/extension/reconciler/RoleReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/RoleReconciler.java index 11f161932..6de02fdae 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/RoleReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/RoleReconciler.java @@ -9,9 +9,12 @@ import java.util.Objects; import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; import run.halo.app.core.extension.Role; import run.halo.app.core.extension.service.RoleService; import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.controller.Reconciler.Request; import run.halo.app.infra.utils.JsonUtils; @@ -23,6 +26,7 @@ import run.halo.app.infra.utils.JsonUtils; * @since 2.0.0 */ @Slf4j +@Component public class RoleReconciler implements Reconciler { private final ExtensionClient client; @@ -65,6 +69,13 @@ public class RoleReconciler implements Reconciler { return new Result(false, null); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new Role()) + .build(); + } + private List aggregateUiPermissions(List dependencyRoles) { return dependencyRoles.stream() .filter(role -> role.getMetadata().getAnnotations() != null) diff --git a/src/main/java/run/halo/app/core/extension/reconciler/SinglePageReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/SinglePageReconciler.java index 9709c5615..546a041ae 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/SinglePageReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/SinglePageReconciler.java @@ -14,6 +14,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.jsoup.Jsoup; import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; import org.springframework.util.Assert; import run.halo.app.content.ContentService; import run.halo.app.content.permalinks.ExtensionLocator; @@ -26,6 +27,8 @@ import run.halo.app.extension.ExtensionOperator; import run.halo.app.extension.ExtensionUtil; import run.halo.app.extension.GroupVersionKind; import run.halo.app.extension.Ref; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.infra.Condition; import run.halo.app.infra.ConditionList; @@ -51,6 +54,7 @@ import run.halo.app.theme.router.PermalinkIndexDeleteCommand; */ @Slf4j @AllArgsConstructor +@Component public class SinglePageReconciler implements Reconciler { private static final String FINALIZER_NAME = "single-page-protection"; private static final GroupVersionKind GVK = GroupVersionKind.fromExtension(SinglePage.class); @@ -81,6 +85,13 @@ public class SinglePageReconciler implements Reconciler { return new Result(false, null); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new SinglePage()) + .build(); + } + private void reconcileSpec(String name) { client.fetch(SinglePage.class, name).ifPresent(page -> { // un-publish if necessary diff --git a/src/main/java/run/halo/app/core/extension/reconciler/SystemSettingReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/SystemSettingReconciler.java index 46f4830a5..f3f7638fd 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/SystemSettingReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/SystemSettingReconciler.java @@ -8,9 +8,12 @@ import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; import run.halo.app.extension.ConfigMap; import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.Metadata; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemSetting; @@ -26,6 +29,7 @@ import run.halo.app.theme.router.PermalinkRuleChangedEvent; * @since 2.0.0 */ @Slf4j +@Component public class SystemSettingReconciler implements Reconciler { public static final String OLD_THEME_ROUTE_RULES = "halo.run/old-theme-route-rules"; public static final String FINALIZER_NAME = "system-setting-protection"; @@ -59,6 +63,13 @@ public class SystemSettingReconciler implements Reconciler { return new Result(false, null); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new ConfigMap()) + .build(); + } + private void customizeSystem(String name) { if (!SystemSetting.SYSTEM_CONFIG_DEFAULT.equals(name)) { return; diff --git a/src/main/java/run/halo/app/core/extension/reconciler/TagReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/TagReconciler.java index 74316cdd6..407403cb1 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/TagReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/TagReconciler.java @@ -5,10 +5,13 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; +import org.springframework.stereotype.Component; import run.halo.app.content.permalinks.TagPermalinkPolicy; import run.halo.app.core.extension.Post; import run.halo.app.core.extension.Tag; import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.infra.utils.JsonUtils; @@ -18,6 +21,7 @@ import run.halo.app.infra.utils.JsonUtils; * @author guqing * @since 2.0.0 */ +@Component public class TagReconciler implements Reconciler { private static final String FINALIZER_NAME = "tag-protection"; private final ExtensionClient client; @@ -46,6 +50,13 @@ public class TagReconciler implements Reconciler { .orElseGet(() -> new Result(false, null)); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new Tag()) + .build(); + } + private void cleanUpResources(Tag tag) { // remove permalink from permalink indexer tagPermalinkPolicy.onPermalinkDelete(tag); diff --git a/src/main/java/run/halo/app/core/extension/reconciler/ThemeReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/ThemeReconciler.java index 9e3aa5149..c503dc6bc 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/ThemeReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/ThemeReconciler.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.FileSystemUtils; import run.halo.app.core.extension.Setting; @@ -16,6 +17,8 @@ import run.halo.app.core.extension.Theme; import run.halo.app.extension.ConfigMap; import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.Metadata; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.controller.Reconciler.Request; import run.halo.app.infra.exception.ThemeUninstallException; @@ -29,6 +32,7 @@ import run.halo.app.theme.ThemePathPolicy; * @author guqing * @since 2.0.0 */ +@Component public class ThemeReconciler implements Reconciler { private final ExtensionClient client; @@ -52,6 +56,13 @@ public class ThemeReconciler implements Reconciler { return new Result(false, null); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new Theme()) + .build(); + } + private void reconcileStatus(String name) { client.fetch(Theme.class, name).ifPresent(theme -> { Theme oldTheme = JsonUtils.deepCopy(theme); diff --git a/src/main/java/run/halo/app/core/extension/reconciler/UserReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/UserReconciler.java index dfa2639af..5aed2b27b 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/UserReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/UserReconciler.java @@ -1,11 +1,16 @@ package run.halo.app.core.extension.reconciler; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import run.halo.app.core.extension.User; import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.controller.Reconciler.Request; @Slf4j +@Component public class UserReconciler implements Reconciler { private final ExtensionClient client; @@ -20,4 +25,11 @@ public class UserReconciler implements Reconciler { return new Result(false, null); } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new User()) + .build(); + } + } diff --git a/src/main/java/run/halo/app/core/extension/reconciler/attachment/AttachmentReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/attachment/AttachmentReconciler.java index e020d90c9..f17df567a 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/attachment/AttachmentReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/attachment/AttachmentReconciler.java @@ -6,6 +6,7 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; import org.springframework.web.util.UriUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -17,6 +18,8 @@ import run.halo.app.core.extension.attachment.endpoint.AttachmentHandler; import run.halo.app.core.extension.attachment.endpoint.AttachmentHandler.DeleteOption; import run.halo.app.extension.ConfigMap; import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.controller.Reconciler.Request; import run.halo.app.infra.ExternalUrlSupplier; @@ -24,6 +27,7 @@ import run.halo.app.infra.exception.NotFoundException; import run.halo.app.plugin.ExtensionComponentsFinder; @Slf4j +@Component public class AttachmentReconciler implements Reconciler { private final ExtensionClient client; @@ -92,6 +96,13 @@ public class AttachmentReconciler implements Reconciler { return null; } + @Override + public Controller setupWith(ControllerBuilder builder) { + return builder + .extension(new Attachment()) + .build(); + } + void updateStatus(String attachmentName, AttachmentStatus status) { client.fetch(Attachment.class, attachmentName) .filter(attachment -> !Objects.deepEquals(attachment.getStatus(), status)) diff --git a/src/main/java/run/halo/app/extension/controller/ControllerBuilder.java b/src/main/java/run/halo/app/extension/controller/ControllerBuilder.java index 4c30881ef..337fdc7bb 100644 --- a/src/main/java/run/halo/app/extension/controller/ControllerBuilder.java +++ b/src/main/java/run/halo/app/extension/controller/ControllerBuilder.java @@ -37,10 +37,11 @@ public class ControllerBuilder { private int workerCount = 1; - public ControllerBuilder(String name, ExtensionClient client) { - Assert.hasText(name, "Extension name is required"); + public ControllerBuilder(Reconciler reconciler, ExtensionClient client) { + Assert.notNull(reconciler, "Reconciler must not be null"); Assert.notNull(client, "Extension client must not be null"); - this.name = name; + this.name = reconciler.getClass().getName(); + this.reconciler = reconciler; this.client = client; } @@ -54,11 +55,6 @@ public class ControllerBuilder { return this; } - public ControllerBuilder reconciler(Reconciler reconciler) { - this.reconciler = reconciler; - return this; - } - public ControllerBuilder nowSupplier(Supplier nowSupplier) { this.nowSupplier = nowSupplier; return this; diff --git a/src/main/java/run/halo/app/extension/controller/ControllerManager.java b/src/main/java/run/halo/app/extension/controller/ControllerManager.java index ee6f42523..2be487c31 100644 --- a/src/main/java/run/halo/app/extension/controller/ControllerManager.java +++ b/src/main/java/run/halo/app/extension/controller/ControllerManager.java @@ -1,42 +1,19 @@ package run.halo.app.extension.controller; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ApplicationListener; +public interface ControllerManager { -@Slf4j -public class ControllerManager implements ApplicationListener, - ApplicationContextAware, DisposableBean { + /** + * Register and start a reconciler. + * + * @param reconciler reconciler must not be null. + */ + void start(Reconciler reconciler); - private ApplicationContext applicationContext; + /** + * Unregister and stop a reconciler. + * + * @param reconciler reconciler must not be null. + */ + void stop(Reconciler reconciler); - @Override - public void onApplicationEvent(ApplicationReadyEvent event) { - applicationContext.getBeansOfType(Controller.class).values().forEach(Controller::start); - } - - @Override - public void destroy() { - var controllers = - applicationContext.getBeansOfType(Controller.class).values(); - log.info("Shutting down {} controllers...", controllers.size()); - controllers.forEach( - controller -> { - try { - controller.dispose(); - } catch (Throwable t) { - log.error("Failed to dispose controller {}", controller.getName(), t); - } - }); - log.info("Shutdown {} controllers.", controllers.size()); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } } diff --git a/src/main/java/run/halo/app/extension/controller/DefaultControllerManager.java b/src/main/java/run/halo/app/extension/controller/DefaultControllerManager.java new file mode 100644 index 000000000..a6d68526c --- /dev/null +++ b/src/main/java/run/halo/app/extension/controller/DefaultControllerManager.java @@ -0,0 +1,83 @@ +package run.halo.app.extension.controller; + +import static org.springframework.core.ResolvableType.forClassWithGenerics; + +import java.util.concurrent.ConcurrentHashMap; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationListener; +import run.halo.app.extension.ExtensionClient; +import run.halo.app.extension.controller.Reconciler.Request; +import run.halo.app.infra.SchemeInitializedEvent; + +@Slf4j +public class DefaultControllerManager + implements ApplicationListener, + ApplicationContextAware, DisposableBean, ControllerManager { + + private final ExtensionClient client; + + private ApplicationContext applicationContext; + + /** + * Map with key: reconciler class name, value: controller self. + */ + private final ConcurrentHashMap controllers; + + public DefaultControllerManager(ExtensionClient client) { + this.client = client; + controllers = new ConcurrentHashMap<>(); + } + + @Override + public void start(Reconciler reconciler) { + var builder = new ControllerBuilder(reconciler, client); + var controller = reconciler.setupWith(builder); + controllers.put(reconciler.getClass().getName(), controller); + controller.start(); + } + + @Override + public void stop(Reconciler reconciler) { + var controller = controllers.remove(reconciler.getClass().getName()); + // destroy it + disposeSilently(controller); + } + + private static void disposeSilently(Controller controller) { + if (controller == null) { + return; + } + try { + log.info("Shutting down controller {}...", controller.getName()); + controller.dispose(); + log.info("Shutdown controller {} successfully", controller.getName()); + } catch (Throwable t) { + log.error("Failed to dispose controller {}", controller.getName(), t); + } + } + + @Override + public void destroy() { + log.info("Shutting down {} controllers...", controllers.size()); + controllers.forEach((name, controller) -> disposeSilently(controller)); + log.info("Shutdown {} controllers.", controllers.size()); + } + + @Override + public void onApplicationEvent(SchemeInitializedEvent event) { + // register reconcilers in system after scheme initialized + applicationContext.>getBeanProvider( + forClassWithGenerics(Reconciler.class, Request.class)) + .orderedStream() + .forEach(this::start); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } +} diff --git a/src/main/java/run/halo/app/extension/controller/Reconciler.java b/src/main/java/run/halo/app/extension/controller/Reconciler.java index 65f1a4490..1dfe6e88e 100644 --- a/src/main/java/run/halo/app/extension/controller/Reconciler.java +++ b/src/main/java/run/halo/app/extension/controller/Reconciler.java @@ -6,6 +6,8 @@ public interface Reconciler { Result reconcile(R request); + Controller setupWith(ControllerBuilder builder); + record Request(String name) { } diff --git a/src/main/java/run/halo/app/extension/gc/GarbageCollectorConfiguration.java b/src/main/java/run/halo/app/extension/gc/GarbageCollectorConfiguration.java deleted file mode 100644 index af46b7db6..000000000 --- a/src/main/java/run/halo/app/extension/gc/GarbageCollectorConfiguration.java +++ /dev/null @@ -1,36 +0,0 @@ -package run.halo.app.extension.gc; - -import java.time.Duration; -import java.time.Instant; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import run.halo.app.extension.ExtensionClient; -import run.halo.app.extension.ExtensionConverter; -import run.halo.app.extension.SchemeManager; -import run.halo.app.extension.controller.Controller; -import run.halo.app.extension.controller.DefaultController; -import run.halo.app.extension.controller.DefaultDelayQueue; -import run.halo.app.extension.store.ExtensionStoreClient; - -@Configuration(proxyBeanMethods = false) -public class GarbageCollectorConfiguration { - - @Bean - Controller garbageCollector(ExtensionClient client, - ExtensionStoreClient storeClient, - ExtensionConverter converter, - SchemeManager schemeManager) { - var reconciler = new GcReconciler(client, storeClient, converter); - var queue = new DefaultDelayQueue(Instant::now, Duration.ofMillis(500)); - var synchronizer = new GcSynchronizer(client, queue, schemeManager); - return new DefaultController<>( - "garbage-collector-controller", - reconciler, - queue, - synchronizer, - Duration.ofMillis(500), - Duration.ofSeconds(1000), - // TODO Make it configurable - 10); - } -} diff --git a/src/main/java/run/halo/app/extension/gc/GcControllerInitializer.java b/src/main/java/run/halo/app/extension/gc/GcControllerInitializer.java new file mode 100644 index 000000000..a20d82b93 --- /dev/null +++ b/src/main/java/run/halo/app/extension/gc/GcControllerInitializer.java @@ -0,0 +1,28 @@ +package run.halo.app.extension.gc; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; +import run.halo.app.extension.controller.Controller; +import run.halo.app.infra.SchemeInitializedEvent; + +@Component +public class GcControllerInitializer + implements ApplicationListener, DisposableBean { + + private final Controller gcController; + + public GcControllerInitializer(GcReconciler gcReconciler) { + this.gcController = gcReconciler.setupWith(null); + } + + @Override + public void onApplicationEvent(SchemeInitializedEvent event) { + gcController.start(); + } + + @Override + public void destroy() throws Exception { + gcController.dispose(); + } +} diff --git a/src/main/java/run/halo/app/extension/gc/GcReconciler.java b/src/main/java/run/halo/app/extension/gc/GcReconciler.java index 70d1c309b..44a759cd8 100644 --- a/src/main/java/run/halo/app/extension/gc/GcReconciler.java +++ b/src/main/java/run/halo/app/extension/gc/GcReconciler.java @@ -1,15 +1,24 @@ package run.halo.app.extension.gc; +import java.time.Duration; +import java.time.Instant; import java.util.function.Predicate; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import run.halo.app.extension.Extension; import run.halo.app.extension.ExtensionClient; import run.halo.app.extension.ExtensionConverter; +import run.halo.app.extension.SchemeManager; +import run.halo.app.extension.controller.Controller; +import run.halo.app.extension.controller.ControllerBuilder; +import run.halo.app.extension.controller.DefaultController; +import run.halo.app.extension.controller.DefaultDelayQueue; import run.halo.app.extension.controller.Reconciler; import run.halo.app.extension.store.ExtensionStoreClient; @Slf4j +@Component class GcReconciler implements Reconciler { private final ExtensionClient client; @@ -18,11 +27,14 @@ class GcReconciler implements Reconciler { private final ExtensionConverter converter; + private final SchemeManager schemeManager; + GcReconciler(ExtensionClient client, ExtensionStoreClient storeClient, - ExtensionConverter converter) { + ExtensionConverter converter, SchemeManager schemeManager) { this.client = client; this.storeClient = storeClient; this.converter = converter; + this.schemeManager = schemeManager; } @@ -41,6 +53,21 @@ class GcReconciler implements Reconciler { return null; } + @Override + public Controller setupWith(ControllerBuilder builder) { + var queue = new DefaultDelayQueue(Instant::now, Duration.ofMillis(500)); + var synchronizer = new GcSynchronizer(client, queue, schemeManager); + return new DefaultController<>( + "garbage-collector-controller", + this, + queue, + synchronizer, + Duration.ofMillis(500), + Duration.ofSeconds(1000), + // TODO Make it configurable + 10); + } + private Predicate deletable() { return extension -> CollectionUtils.isEmpty(extension.getMetadata().getFinalizers()) && extension.getMetadata().getDeletionTimestamp() != null; diff --git a/src/test/java/run/halo/app/extension/controller/ControllerBuilderTest.java b/src/test/java/run/halo/app/extension/controller/ControllerBuilderTest.java index ff86c14e8..b22fbb99b 100644 --- a/src/test/java/run/halo/app/extension/controller/ControllerBuilderTest.java +++ b/src/test/java/run/halo/app/extension/controller/ControllerBuilderTest.java @@ -20,28 +20,23 @@ class ControllerBuilderTest { ExtensionClient client; @Test - void buildWithBlankName() { + void buildWithNullReconciler() { assertThrows(IllegalArgumentException.class, - () -> new ControllerBuilder("", client).build()); + () -> new ControllerBuilder(null, client).build(), "Reconciler must not be null"); } @Test void buildWithNullClient() { assertThrows(IllegalArgumentException.class, - () -> new ControllerBuilder("fake-name", null).build()); + () -> new ControllerBuilder(new FakeReconciler(), null).build()); } @Test void buildTest() { assertThrows(IllegalArgumentException.class, - () -> new ControllerBuilder("fake-name", client) + () -> new ControllerBuilder(new FakeReconciler(), client) .build(), "Extension must not be null"); - assertThrows(IllegalArgumentException.class, - () -> new ControllerBuilder("fake-name", client) - .extension(new FakeExtension()) - .build(), - "Reconciler must not be null"); assertNotNull(fakeBuilder().build()); @@ -92,9 +87,21 @@ class ControllerBuilderTest { } ControllerBuilder fakeBuilder() { - return new ControllerBuilder("fake-name", client) - .extension(new FakeExtension()) - .reconciler(request -> new Reconciler.Result(false, null)); + return new ControllerBuilder(new FakeReconciler(), client) + .extension(new FakeExtension()); + } + + static class FakeReconciler implements Reconciler { + + @Override + public Result reconcile(Request request) { + return new Reconciler.Result(false, null); + } + + @Override + public Controller setupWith(ControllerBuilder builder) { + return null; + } } } \ No newline at end of file