diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutor.java b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutor.java index a107301d..011e4148 100644 --- a/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutor.java +++ b/hippo4j-core/src/main/java/cn/hippo4j/core/executor/DynamicThreadPoolExecutor.java @@ -29,6 +29,7 @@ import lombok.NonNull; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.DisposableBean; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.task.TaskDecorator; import java.util.Objects; @@ -88,7 +89,7 @@ public class DynamicThreadPoolExecutor extends ExtensibleThreadPoolExecutor impl @NonNull ThreadFactory threadFactory, @NonNull RejectedExecutionHandler rejectedExecutionHandler) { super( - threadPoolId, new DefaultThreadPoolPluginManager().setEnableSort(true), + threadPoolId, new DefaultThreadPoolPluginManager().setPluginComparator(AnnotationAwareOrderComparator.INSTANCE), corePoolSize, maximumPoolSize, keepAliveTime, unit, blockingQueue, threadFactory, rejectedExecutionHandler); log.info("Initializing ExecutorService {}", threadPoolId); diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManager.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManager.java index f2f6eebb..790ed894 100644 --- a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManager.java +++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManager.java @@ -26,17 +26,23 @@ import cn.hippo4j.core.plugin.ThreadPoolPlugin; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -49,72 +55,107 @@ import java.util.stream.Collectors; * or bound to an {@link java.util.concurrent.ThreadPoolExecutor} instance through {@link ThreadPoolPluginSupport} * to support its plugin based extension functions. * - *

When {@link #isEnableSort()} is true, plugins can be obtained in batches - * in the order specified by {@link AnnotationAwareOrderComparator}.
- * When the sorting function is enabled through {@link #setEnableSort} for the first time, + *

Order of plugin

+ *

By default, plugins are installed in the order in which they are registered. + * When {@link #isEnableSort()} is true, plugins can be obtained in batches + * in the order specified by {@link #pluginComparator}(if not null).
+ * When the sorting function is enabled through {@link #setPluginComparator} for the first time, * all registered plugins will be sorted, * Later, whenever a new plug-in is registered, all plug-ins will be reordered again. * - *

NOTE: - * When the list of plugins is obtained through the {@code getXXX} method of manager, the list is not immutable. + *

Status of the plugin

+ *

The plugins registered in the container can be divided into two states: enabled and disabled, + * Plugins that are disabled cannot be obtained through the following methods: + *

+ * Generally, plugins in disabled status will not be used by {@link ThreadPoolPluginSupport}. + * users can switch the status of plugins through {@link #enable} and {@link #disable} methods. + * + *

Thread-safe operation support

+ *

When the list of plugins is obtained through the {@code getXXX} method of manager, the list is not immutable. * This means that until actually start iterating over the list, * registering or unregistering plugins through the manager will affect the results of the iteration. * Therefore, we should try to ensure that get the latest plugin list from the manager before each use. * * @see cn.hippo4j.core.executor.DynamicThreadPoolExecutor * @see cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor - * @see AnnotationAwareOrderComparator */ public class DefaultThreadPoolPluginManager implements ThreadPoolPluginManager { /** * Lock of this instance */ - private final ReadWriteLockSupport mainLock = new ReadWriteLockSupport(new ReentrantReadWriteLock()); + private final ReadWriteLockSupport mainLock; /** - * Registered {@link ThreadPoolPlugin} + * All registered {@link ThreadPoolPlugin} */ private final Map registeredPlugins = new ConcurrentHashMap<>(16); /** - * Registered {@link TaskAwarePlugin} + * Disabled plugins. + */ + private final Set disabledPlugins = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); + + /** + * Index of enabled {@link TaskAwarePlugin} + */ + private final QuickIndex taskAwarePluginList = new QuickIndex<>(TaskAwarePlugin.class); + + /** + * Index of enabled {@link ExecuteAwarePlugin} */ - private final List taskAwarePluginList = new CopyOnWriteArrayList<>(); + private final QuickIndex executeAwarePluginList = new QuickIndex<>(ExecuteAwarePlugin.class); /** - * Registered {@link ExecuteAwarePlugin} + * Index of enabled {@link RejectedAwarePlugin} */ - private final List executeAwarePluginList = new CopyOnWriteArrayList<>(); + private final QuickIndex rejectedAwarePluginList = new QuickIndex<>(RejectedAwarePlugin.class); /** - * Registered {@link RejectedAwarePlugin} + * Index of enabled {@link ShutdownAwarePlugin} */ - private final List rejectedAwarePluginList = new CopyOnWriteArrayList<>(); + private final QuickIndex shutdownAwarePluginList = new QuickIndex<>(ShutdownAwarePlugin.class); /** - * Registered {@link ShutdownAwarePlugin} + * Comparator of {@link ThreadPoolPlugin}. */ - private final List shutdownAwarePluginList = new CopyOnWriteArrayList<>(); + private Comparator pluginComparator; /** - * Enable sort. + * Create a {@link DefaultThreadPoolPluginManager}, + * By default, plugins are not sorted, + * and thread safety is implemented based on {@link ReentrantReadWriteLock}. */ - @Getter - private boolean enableSort = false; + public DefaultThreadPoolPluginManager() { + this(new ReentrantReadWriteLock(), null); + } + + /** + * Create a {@link DefaultThreadPoolPluginManager}. + * + * @param mainLock main lock + * @param pluginComparator comparator of plugin + */ + public DefaultThreadPoolPluginManager( + @NonNull ReadWriteLock mainLock, @Nullable Comparator pluginComparator) { + this.pluginComparator = pluginComparator; + this.mainLock = new ReadWriteLockSupport(mainLock); + } /** * Clear all. */ @Override - public synchronized void clear() { + public void clear() { mainLock.runWithWriteLock(() -> { - Collection plugins = registeredPlugins.values(); + Collection plugins = new ArrayList<>(registeredPlugins.values()); registeredPlugins.clear(); - taskAwarePluginList.clear(); - executeAwarePluginList.clear(); - rejectedAwarePluginList.clear(); - shutdownAwarePluginList.clear(); + forQuickIndexes(QuickIndex::clear); plugins.forEach(ThreadPoolPlugin::stop); }); } @@ -126,7 +167,6 @@ public class DefaultThreadPoolPluginManager implements ThreadPoolPluginManager { * @throws IllegalArgumentException thrown when a plugin with the same {@link ThreadPoolPlugin#getId()} already exists in the registry * @see ThreadPoolPlugin#getId() * @see #isEnableSort - * @see AnnotationAwareOrderComparator#sort(List) */ @Override public void register(@NonNull ThreadPoolPlugin plugin) { @@ -134,30 +174,7 @@ public class DefaultThreadPoolPluginManager implements ThreadPoolPluginManager { String id = plugin.getId(); Assert.isTrue(!isRegistered(id), "The plugin with id [" + id + "] has been registered"); registeredPlugins.put(id, plugin); - if (plugin instanceof TaskAwarePlugin) { - taskAwarePluginList.add((TaskAwarePlugin) plugin); - if (enableSort) { - AnnotationAwareOrderComparator.sort(taskAwarePluginList); - } - } - if (plugin instanceof ExecuteAwarePlugin) { - executeAwarePluginList.add((ExecuteAwarePlugin) plugin); - if (enableSort) { - AnnotationAwareOrderComparator.sort(executeAwarePluginList); - } - } - if (plugin instanceof RejectedAwarePlugin) { - rejectedAwarePluginList.add((RejectedAwarePlugin) plugin); - if (enableSort) { - AnnotationAwareOrderComparator.sort(rejectedAwarePluginList); - } - } - if (plugin instanceof ShutdownAwarePlugin) { - shutdownAwarePluginList.add((ShutdownAwarePlugin) plugin); - if (enableSort) { - AnnotationAwareOrderComparator.sort(shutdownAwarePluginList); - } - } + forQuickIndexes(quickIndex -> quickIndex.addIfPossible(plugin)); plugin.start(); }); } @@ -190,22 +207,69 @@ public class DefaultThreadPoolPluginManager implements ThreadPoolPluginManager { () -> Optional.ofNullable(pluginId) .map(registeredPlugins::remove) .ifPresent(plugin -> { - if (plugin instanceof TaskAwarePlugin) { - taskAwarePluginList.remove(plugin); - } - if (plugin instanceof ExecuteAwarePlugin) { - executeAwarePluginList.remove(plugin); - } - if (plugin instanceof RejectedAwarePlugin) { - rejectedAwarePluginList.remove(plugin); - } - if (plugin instanceof ShutdownAwarePlugin) { - shutdownAwarePluginList.remove(plugin); - } + disabledPlugins.remove(pluginId); + forQuickIndexes(quickIndex -> quickIndex.removeIfPossible(plugin)); plugin.stop(); })); } + /** + * Get id of disabled plugins. + * + * @return id of disabled plugins + */ + @Override + public Set getAllDisabledPluginIds() { + return disabledPlugins; + } + + /** + * Whether the plugin has been disabled. + * + * @param pluginId plugin id + * @return true if plugin has been disabled, false otherwise + */ + @Override + public boolean isDisabled(String pluginId) { + return disabledPlugins.contains(pluginId); + } + + /** + * Enable plugin, make plugins will allow access through quick indexes. + * + * @param pluginId plugin id + * @return true if plugin already registered or enabled, false otherwise + */ + @Override + public boolean enable(String pluginId) { + return mainLock.applyWithReadLock(() -> { + ThreadPoolPlugin plugin = registeredPlugins.get(pluginId); + if (Objects.isNull(plugin) || !disabledPlugins.remove(pluginId)) { + return false; + } + forQuickIndexes(quickIndex -> quickIndex.addIfPossible(plugin)); + return true; + }); + } + + /** + * Disable plugin, make plugins will not allow access through quick indexes. + * + * @param pluginId plugin id + * @return true if plugin already registered or disabled, false otherwise + */ + @Override + public boolean disable(String pluginId) { + return mainLock.applyWithReadLock(() -> { + ThreadPoolPlugin plugin = registeredPlugins.get(pluginId); + if (Objects.isNull(plugin) || !disabledPlugins.add(pluginId)) { + return false; + } + forQuickIndexes(quickIndex -> quickIndex.removeIfPossible(plugin)); + return true; + }); + } + /** * Get all registered plugins. * @@ -217,9 +281,9 @@ public class DefaultThreadPoolPluginManager implements ThreadPoolPluginManager { public Collection getAllPlugins() { return mainLock.applyWithReadLock(() -> { // sort if necessary - if (enableSort) { + if (isEnableSort()) { return registeredPlugins.values().stream() - .sorted(AnnotationAwareOrderComparator.INSTANCE) + .sorted(pluginComparator) .collect(Collectors.toList()); } return registeredPlugins.values(); @@ -252,49 +316,68 @@ public class DefaultThreadPoolPluginManager implements ThreadPoolPluginManager { } /** - * Get execute plugin list. + * Get all enabled {@link ExecuteAwarePlugin}. * * @return {@link ExecuteAwarePlugin} + * @apiNote Be sure to avoid directly modifying returned collection instances, + * otherwise, unexpected results may be obtained through the manager + * @see #enable + * @see #disable */ @Override public Collection getExecuteAwarePluginList() { - return mainLock.applyWithReadLock(() -> executeAwarePluginList); + return mainLock.applyWithReadLock(executeAwarePluginList::getPlugins); } /** - * Get rejected plugin list. + * Get all enabled {@link RejectedAwarePlugin}. * * @return {@link RejectedAwarePlugin} * @apiNote Be sure to avoid directly modifying returned collection instances, * otherwise, unexpected results may be obtained through the manager + * @see #enable + * @see #disable */ @Override public Collection getRejectedAwarePluginList() { - return mainLock.applyWithReadLock(() -> rejectedAwarePluginList); + return mainLock.applyWithReadLock(rejectedAwarePluginList::getPlugins); } /** - * Get shutdown plugin list. + * Get all enabled {@link ShutdownAwarePlugin}. * * @return {@link ShutdownAwarePlugin} * @apiNote Be sure to avoid directly modifying returned collection instances, * otherwise, unexpected results may be obtained through the manager + * @see #enable + * @see #disable */ @Override public Collection getShutdownAwarePluginList() { - return mainLock.applyWithReadLock(() -> shutdownAwarePluginList); + return mainLock.applyWithReadLock(shutdownAwarePluginList::getPlugins); } /** - * Get shutdown plugin list. + * Get all enabled {@link TaskAwarePlugin}. * - * @return {@link ShutdownAwarePlugin} + * @return {@link TaskAwarePlugin} * @apiNote Be sure to avoid directly modifying returned collection instances, * otherwise, unexpected results may be obtained through the manager + * @see #enable + * @see #disable */ @Override public Collection getTaskAwarePluginList() { - return mainLock.applyWithReadLock(() -> taskAwarePluginList); + return mainLock.applyWithReadLock(taskAwarePluginList::getPlugins); + } + + /** + * Whether sorting plugins is allowed. + * + * @return true if sorting plugins is allowed, false otherwise + */ + public boolean isEnableSort() { + return Objects.nonNull(pluginComparator); } /** @@ -303,27 +386,94 @@ public class DefaultThreadPoolPluginManager implements ThreadPoolPluginManager { * If {@link #isEnableSort} returns false and {@code enableSort} is true, * All currently registered plug-ins will be reordered immediately. * - * @param enableSort enable sort + * @param comparator comparator of plugins * @return {@link DefaultThreadPoolPluginManager} - * @see AnnotationAwareOrderComparator#sort(List) */ - public DefaultThreadPoolPluginManager setEnableSort(boolean enableSort) { - // if it was unordered before, it needs to be reordered now - if (!isEnableSort() && enableSort) { - mainLock.runWithWriteLock(() -> { - // if it has been successfully updated, there is no need to operate again - if (this.enableSort != enableSort) { - AnnotationAwareOrderComparator.sort(taskAwarePluginList); - AnnotationAwareOrderComparator.sort(executeAwarePluginList); - AnnotationAwareOrderComparator.sort(rejectedAwarePluginList); - AnnotationAwareOrderComparator.sort(shutdownAwarePluginList); - } - }); - } - this.enableSort = enableSort; + public DefaultThreadPoolPluginManager setPluginComparator(@NonNull Comparator comparator) { + mainLock.runWithWriteLock(() -> { + // the specified comparator has been set + if (Objects.equals(this.pluginComparator, comparator)) { + return; + } + this.pluginComparator = comparator; + forQuickIndexes(QuickIndex::sort); + }); return this; } + /** + * operate for each indexes + */ + private void forQuickIndexes(Consumer> consumer) { + consumer.accept(taskAwarePluginList); + consumer.accept(executeAwarePluginList); + consumer.accept(rejectedAwarePluginList); + consumer.accept(shutdownAwarePluginList); + } + + /** + * Quick index of registered {@link ThreadPoolPlugin} + * + * @param plugin type + */ + @RequiredArgsConstructor + private class QuickIndex { + + /** + * Plugin type + */ + private final Class pluginType; + + /** + * Plugins + */ + @Getter + private final List plugins = new CopyOnWriteArrayList<>(); + + /** + * Add plugin if possible. + * + * @param plugin plugin + */ + public void addIfPossible(ThreadPoolPlugin plugin) { + if (!pluginType.isInstance(plugin)) { + return; + } + plugins.add(pluginType.cast(plugin)); + sort(); + } + + /** + * Remove plugin if possible. + * + * @param plugin plugin + */ + public void removeIfPossible(ThreadPoolPlugin plugin) { + if (!pluginType.isInstance(plugin)) { + return; + } + plugins.remove(pluginType.cast(plugin)); + sort(); + } + + /** + * Sort by {@link #pluginComparator}. + */ + public void sort() { + if (isEnableSort()) { + plugins.sort(pluginComparator); + } + } + + /** + * Clear all. + */ + public void clear() { + plugins.clear(); + } + + } + /** * Read write lock support. */ @@ -381,4 +531,5 @@ public class DefaultThreadPoolPluginManager implements ThreadPoolPluginManager { } } + } diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManager.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManager.java index e03f111d..d2d18ea3 100644 --- a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManager.java +++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManager.java @@ -17,13 +17,18 @@ package cn.hippo4j.core.plugin.manager; -import cn.hippo4j.core.plugin.*; +import cn.hippo4j.core.plugin.ExecuteAwarePlugin; +import cn.hippo4j.core.plugin.RejectedAwarePlugin; +import cn.hippo4j.core.plugin.ShutdownAwarePlugin; +import cn.hippo4j.core.plugin.TaskAwarePlugin; +import cn.hippo4j.core.plugin.ThreadPoolPlugin; import lombok.AccessLevel; import lombok.NoArgsConstructor; import java.util.Collection; import java.util.Collections; import java.util.Optional; +import java.util.Set; /** * Empty thread pool plugin manager. @@ -96,6 +101,49 @@ public class EmptyThreadPoolPluginManager implements ThreadPoolPluginManager { public void unregister(String pluginId) { } + /** + * Get id of disabled plugins. + * + * @return id of disabled plugins + */ + @Override + public Set getAllDisabledPluginIds() { + return Collections.emptySet(); + } + + /** + * Whether the plugin has been disabled. + * + * @param pluginId plugin id + * @return true if plugin has been disabled, false otherwise + */ + @Override + public boolean isDisabled(String pluginId) { + return true; + } + + /** + * Enable plugin, make plugins will allow access through quick indexes. + * + * @param pluginId plugin id + * @return true if plugin already registered or enabled, false otherwise + */ + @Override + public boolean enable(String pluginId) { + return false; + } + + /** + * Disable plugin, make plugins will not allow access through quick indexes. + * + * @param pluginId plugin id + * @return true if plugin already registered or disabled, false otherwise + */ + @Override + public boolean disable(String pluginId) { + return false; + } + /** * Get {@link ThreadPoolPlugin}. * @@ -109,9 +157,11 @@ public class EmptyThreadPoolPluginManager implements ThreadPoolPluginManager { } /** - * Get execute aware plugin list. + * Get all enabled {@link ExecuteAwarePlugin}. * * @return {@link ExecuteAwarePlugin} + * @see #enable + * @see #disable */ @Override public Collection getExecuteAwarePluginList() { @@ -119,9 +169,11 @@ public class EmptyThreadPoolPluginManager implements ThreadPoolPluginManager { } /** - * Get rejected aware plugin list. + * Get all enabled {@link RejectedAwarePlugin}. * * @return {@link RejectedAwarePlugin} + * @see #enable + * @see #disable */ @Override public Collection getRejectedAwarePluginList() { @@ -129,9 +181,11 @@ public class EmptyThreadPoolPluginManager implements ThreadPoolPluginManager { } /** - * Get shutdown aware plugin list. + * Get all enabled {@link ShutdownAwarePlugin}. * * @return {@link ShutdownAwarePlugin} + * @see #enable + * @see #disable */ @Override public Collection getShutdownAwarePluginList() { @@ -139,9 +193,11 @@ public class EmptyThreadPoolPluginManager implements ThreadPoolPluginManager { } /** - * Get shutdown aware plugin list. + * Get all enabled {@link TaskAwarePlugin}. * - * @return {@link ShutdownAwarePlugin} + * @return {@link TaskAwarePlugin} + * @see #enable + * @see #disable */ @Override public Collection getTaskAwarePluginList() { diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginManager.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginManager.java index 74f36cc1..56027c2b 100644 --- a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginManager.java +++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginManager.java @@ -17,14 +17,20 @@ package cn.hippo4j.core.plugin.manager; -import cn.hippo4j.core.plugin.*; +import cn.hippo4j.core.plugin.ExecuteAwarePlugin; +import cn.hippo4j.core.plugin.PluginRuntime; +import cn.hippo4j.core.plugin.RejectedAwarePlugin; +import cn.hippo4j.core.plugin.ShutdownAwarePlugin; +import cn.hippo4j.core.plugin.TaskAwarePlugin; +import cn.hippo4j.core.plugin.ThreadPoolPlugin; import java.util.Collection; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; /** - * Manager of {@link ThreadPoolPlugin}. + *

Manager of {@link ThreadPoolPlugin}.
* Bind with the specified thread-pool instance to register and manage plugins. * when the thread pool is destroyed, please ensure that the manager will also be destroyed. * @@ -87,7 +93,38 @@ public interface ThreadPoolPluginManager { void unregister(String pluginId); /** - * Get {@link ThreadPoolPlugin}. + * Get id of disabled plugins. + * + * @return id of disabled plugins + */ + Set getAllDisabledPluginIds(); + + /** + * Whether the plugin has been disabled. + * + * @param pluginId plugin id + * @return true if plugin has been disabled, false otherwise + */ + boolean isDisabled(String pluginId); + + /** + * Enable plugin, make plugins will allow access through quick indexes. + * + * @param pluginId plugin id + * @return true if plugin already registered or enabled, false otherwise + */ + boolean enable(String pluginId); + + /** + * Disable plugin, make plugins will not allow access through quick indexes. + * + * @param pluginId plugin id + * @return true if plugin already registered or disabled, false otherwise + */ + boolean disable(String pluginId); + + /** + * Get registered {@link ThreadPoolPlugin}. * * @param pluginId plugin id * @param target aware type @@ -97,30 +134,38 @@ public interface ThreadPoolPluginManager { Optional getPlugin(String pluginId); /** - * Get execute aware plugin list. + * Get all enabled {@link ExecuteAwarePlugin}. * * @return {@link ExecuteAwarePlugin} + * @see #enable + * @see #disable */ Collection getExecuteAwarePluginList(); /** - * Get rejected aware plugin list. + * Get all enabled {@link RejectedAwarePlugin}. * * @return {@link RejectedAwarePlugin} + * @see #enable + * @see #disable */ Collection getRejectedAwarePluginList(); /** - * Get shutdown aware plugin list. + * Get all enabled {@link ShutdownAwarePlugin}. * * @return {@link ShutdownAwarePlugin} + * @see #enable + * @see #disable */ Collection getShutdownAwarePluginList(); /** - * Get shutdown aware plugin list. + * Get all enabled {@link TaskAwarePlugin}. * - * @return {@link ShutdownAwarePlugin} + * @return {@link TaskAwarePlugin} + * @see #enable + * @see #disable */ Collection getTaskAwarePluginList(); diff --git a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupport.java b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupport.java index 20d6d195..31426421 100644 --- a/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupport.java +++ b/hippo4j-core/src/main/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupport.java @@ -17,11 +17,16 @@ package cn.hippo4j.core.plugin.manager; -import cn.hippo4j.core.plugin.*; +import cn.hippo4j.core.plugin.ExecuteAwarePlugin; +import cn.hippo4j.core.plugin.RejectedAwarePlugin; +import cn.hippo4j.core.plugin.ShutdownAwarePlugin; +import cn.hippo4j.core.plugin.TaskAwarePlugin; +import cn.hippo4j.core.plugin.ThreadPoolPlugin; import org.checkerframework.checker.nullness.qual.NonNull; import java.util.Collection; import java.util.Optional; +import java.util.Set; import java.util.concurrent.ThreadPoolExecutor; /** @@ -126,9 +131,54 @@ public interface ThreadPoolPluginSupport extends ThreadPoolPluginManager { } /** - * Get execute aware list. + * Get id of disabled plugins. + * + * @return id of disabled plugins + */ + @Override + default Set getAllDisabledPluginIds() { + return getThreadPoolPluginManager().getAllDisabledPluginIds(); + } + + /** + * Whether the plugin has been disabled. + * + * @param pluginId plugin id + * @return true if plugin has been disabled, false otherwise + */ + @Override + default boolean isDisabled(String pluginId) { + return getThreadPoolPluginManager().isDisabled(pluginId); + } + + /** + * Enable plugin, make plugins will allow access through quick indexes. + * + * @param pluginId plugin id + * @return true if plugin already registered or enabled, false otherwise + */ + @Override + default boolean enable(String pluginId) { + return getThreadPoolPluginManager().enable(pluginId); + } + + /** + * Disable plugin, make plugins will not allow access through quick indexes. + * + * @param pluginId plugin id + * @return true if plugin already registered or disabled, false otherwise + */ + @Override + default boolean disable(String pluginId) { + return getThreadPoolPluginManager().disable(pluginId); + } + + /** + * Get all enabled {@link ExecuteAwarePlugin}. * * @return {@link ExecuteAwarePlugin} + * @see #enable + * @see #disable */ @Override default Collection getExecuteAwarePluginList() { @@ -136,9 +186,11 @@ public interface ThreadPoolPluginSupport extends ThreadPoolPluginManager { } /** - * Get rejected aware list. + * Get all enabled {@link RejectedAwarePlugin}. * * @return {@link RejectedAwarePlugin} + * @see #enable + * @see #disable */ @Override default Collection getRejectedAwarePluginList() { @@ -146,9 +198,11 @@ public interface ThreadPoolPluginSupport extends ThreadPoolPluginManager { } /** - * Get shutdown aware list. + * Get all enabled {@link ShutdownAwarePlugin}. * * @return {@link ShutdownAwarePlugin} + * @see #enable + * @see #disable */ @Override default Collection getShutdownAwarePluginList() { @@ -156,9 +210,11 @@ public interface ThreadPoolPluginSupport extends ThreadPoolPluginManager { } /** - * Get shutdown aware list. + * Get all enabled {@link TaskAwarePlugin}. * - * @return {@link ShutdownAwarePlugin} + * @return {@link TaskAwarePlugin} + * @see #enable + * @see #disable */ @Override default Collection getTaskAwarePluginList() { diff --git a/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManagerTest.java b/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManagerTest.java index 64b78b79..94ae0e1b 100644 --- a/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManagerTest.java +++ b/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/DefaultThreadPoolPluginManagerTest.java @@ -26,9 +26,11 @@ import lombok.Getter; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.Order; import java.util.Iterator; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** * test for {@link DefaultThreadPoolPluginManager} @@ -39,7 +41,7 @@ public class DefaultThreadPoolPluginManagerTest { @Before public void initRegistry() { - manager = new DefaultThreadPoolPluginManager(); + manager = new DefaultThreadPoolPluginManager(new ReentrantReadWriteLock(), null); } @Test @@ -156,12 +158,58 @@ public class DefaultThreadPoolPluginManagerTest { } @Test - public void testSetEnableSort() { + public void testEnable() { + ThreadPoolPlugin plugin = new TestExecuteAwarePlugin(); + Assert.assertFalse(manager.enable(plugin.getId())); + manager.register(plugin); + Assert.assertFalse(manager.enable(plugin.getId())); + manager.disable(plugin.getId()); + Assert.assertTrue(manager.enable(plugin.getId())); + } + + @Test + public void testDisable() { + ThreadPoolPlugin plugin = new TestExecuteAwarePlugin(); + Assert.assertFalse(manager.disable(plugin.getId())); + + manager.register(plugin); + Assert.assertTrue(manager.disable(plugin.getId())); + Assert.assertFalse(manager.disable(plugin.getId())); + + Assert.assertTrue(manager.getExecuteAwarePluginList().isEmpty()); + Assert.assertEquals(1, manager.getAllPlugins().size()); + } + + @Test + public void testIsDisable() { + ThreadPoolPlugin plugin = new TestExecuteAwarePlugin(); + Assert.assertFalse(manager.isDisabled(plugin.getId())); + + manager.register(plugin); + Assert.assertTrue(manager.disable(plugin.getId())); + Assert.assertTrue(manager.isDisabled(plugin.getId())); + } + + @Test + public void testGetDisabledPluginIds() { + ThreadPoolPlugin plugin = new TestExecuteAwarePlugin(); + Assert.assertTrue(manager.getAllDisabledPluginIds().isEmpty()); + + manager.register(plugin); + Assert.assertTrue(manager.disable(plugin.getId())); + Assert.assertEquals(1, manager.getAllDisabledPluginIds().size()); + } + + @Test + public void testSetPluginComparator() { + Assert.assertFalse(manager.isEnableSort()); + manager.register(new TestExecuteAwarePlugin()); manager.register(new TestTaskAwarePlugin()); - manager.setEnableSort(true); + manager.setPluginComparator(AnnotationAwareOrderComparator.INSTANCE); manager.register(new TestRejectedAwarePlugin()); manager.register(new TestShutdownAwarePlugin()); + Assert.assertTrue(manager.isEnableSort()); Iterator iterator = manager.getAllPlugins().iterator(); Assert.assertEquals(TestTaskAwarePlugin.class, iterator.next().getClass()); diff --git a/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManagerTest.java b/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManagerTest.java index f5e0ac26..be19f091 100644 --- a/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManagerTest.java +++ b/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/EmptyThreadPoolPluginManagerTest.java @@ -97,6 +97,49 @@ public class EmptyThreadPoolPluginManagerTest { Assert.assertEquals(Collections.emptyList(), manager.getExecuteAwarePluginList()); } + @Test + public void testEnable() { + ThreadPoolPlugin plugin = new TestPlugin(); + Assert.assertFalse(manager.enable(plugin.getId())); + manager.register(plugin); + Assert.assertFalse(manager.enable(plugin.getId())); + manager.disable(plugin.getId()); + Assert.assertFalse(manager.enable(plugin.getId())); + } + + @Test + public void testDisable() { + ThreadPoolPlugin plugin = new TestPlugin(); + Assert.assertFalse(manager.disable(plugin.getId())); + + manager.register(plugin); + Assert.assertFalse(manager.disable(plugin.getId())); + Assert.assertFalse(manager.disable(plugin.getId())); + + Assert.assertTrue(manager.getExecuteAwarePluginList().isEmpty()); + Assert.assertTrue(manager.getAllPlugins().isEmpty()); + } + + @Test + public void testIsDisable() { + ThreadPoolPlugin plugin = new TestPlugin(); + Assert.assertTrue(manager.isDisabled(plugin.getId())); + + manager.register(plugin); + Assert.assertFalse(manager.disable(plugin.getId())); + Assert.assertTrue(manager.isDisabled(plugin.getId())); + } + + @Test + public void testGetDisabledPluginIds() { + ThreadPoolPlugin plugin = new TestPlugin(); + Assert.assertTrue(manager.getAllDisabledPluginIds().isEmpty()); + + manager.register(plugin); + Assert.assertFalse(manager.disable(plugin.getId())); + Assert.assertTrue(manager.getAllDisabledPluginIds().isEmpty()); + } + private static boolean isEmpty(ThreadPoolPluginManager manager) { return manager.getAllPlugins().isEmpty(); } diff --git a/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupportTest.java b/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupportTest.java index e92ce58b..92196a5f 100644 --- a/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupportTest.java +++ b/hippo4j-core/src/test/java/cn/hippo4j/core/plugin/manager/ThreadPoolPluginSupportTest.java @@ -18,7 +18,11 @@ package cn.hippo4j.core.plugin.manager; import cn.hippo4j.core.executor.ExtensibleThreadPoolExecutor; -import cn.hippo4j.core.plugin.*; +import cn.hippo4j.core.plugin.ExecuteAwarePlugin; +import cn.hippo4j.core.plugin.RejectedAwarePlugin; +import cn.hippo4j.core.plugin.ShutdownAwarePlugin; +import cn.hippo4j.core.plugin.TaskAwarePlugin; +import cn.hippo4j.core.plugin.ThreadPoolPlugin; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.junit.Assert; @@ -162,6 +166,49 @@ public class ThreadPoolPluginSupportTest { Assert.assertFalse(support.getPluginOfType(TestExecuteAwarePlugin.class.getSimpleName(), RejectedAwarePlugin.class).isPresent()); } + @Test + public void testEnable() { + ThreadPoolPlugin plugin = new TestExecuteAwarePlugin(); + Assert.assertFalse(support.enable(plugin.getId())); + support.register(plugin); + Assert.assertFalse(support.enable(plugin.getId())); + support.disable(plugin.getId()); + Assert.assertTrue(support.enable(plugin.getId())); + } + + @Test + public void testDisable() { + ThreadPoolPlugin plugin = new TestExecuteAwarePlugin(); + Assert.assertFalse(support.disable(plugin.getId())); + + support.register(plugin); + Assert.assertTrue(support.disable(plugin.getId())); + Assert.assertFalse(support.disable(plugin.getId())); + + Assert.assertTrue(support.getExecuteAwarePluginList().isEmpty()); + Assert.assertEquals(1, support.getAllPlugins().size()); + } + + @Test + public void testIsDisable() { + ThreadPoolPlugin plugin = new TestExecuteAwarePlugin(); + Assert.assertFalse(support.isDisabled(plugin.getId())); + + support.register(plugin); + Assert.assertTrue(support.disable(plugin.getId())); + Assert.assertTrue(support.isDisabled(plugin.getId())); + } + + @Test + public void testGetDisabledPluginIds() { + ThreadPoolPlugin plugin = new TestExecuteAwarePlugin(); + Assert.assertTrue(support.getAllDisabledPluginIds().isEmpty()); + + support.register(plugin); + Assert.assertTrue(support.disable(plugin.getId())); + Assert.assertEquals(1, support.getAllDisabledPluginIds().size()); + } + @Getter private final static class TestTaskAwarePlugin implements TaskAwarePlugin {