diff --git a/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java b/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java index 8d0fb1068..4d131d424 100644 --- a/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java +++ b/application/src/main/java/run/halo/app/plugin/HaloPluginManager.java @@ -22,6 +22,7 @@ import org.pf4j.PluginStateEvent; import org.pf4j.PluginStateListener; import org.pf4j.PluginStatusProvider; import org.pf4j.PluginWrapper; +import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.data.util.Lazy; import run.halo.app.infra.SystemVersionSupplier; @@ -36,33 +37,27 @@ import run.halo.app.plugin.event.PluginStartedEvent; * @since 2.0.0 */ @Slf4j -public class HaloPluginManager extends DefaultPluginManager implements SpringPluginManager { +public class HaloPluginManager extends DefaultPluginManager + implements SpringPluginManager, InitializingBean { private final ApplicationContext rootContext; - private final Lazy sharedContext; + private Lazy sharedContext; private final PluginProperties pluginProperties; private final PluginsRootGetter pluginsRootGetter; + private final SystemVersionSupplier systemVersionSupplier; + public HaloPluginManager(ApplicationContext rootContext, PluginProperties pluginProperties, - SystemVersionSupplier systemVersionSupplier, PluginsRootGetter pluginsRootGetter) { + SystemVersionSupplier systemVersionSupplier, + PluginsRootGetter pluginsRootGetter) { this.pluginProperties = pluginProperties; this.rootContext = rootContext; - // We have to initialize share context lazily because the root context has not refreshed - this.sharedContext = Lazy.of(() -> SharedApplicationContextFactory.create(rootContext)); this.pluginsRootGetter = pluginsRootGetter; - super.runtimeMode = pluginProperties.getRuntimeMode(); - - setExactVersionAllowed(pluginProperties.isExactVersionAllowed()); - setSystemVersion(systemVersionSupplier.get().getNormalVersion()); - - super.initialize(); - - // the listener must be after the super#initialize - addPluginStateListener(new PluginStartedListener()); + this.systemVersionSupplier = systemVersionSupplier; } @Override @@ -71,6 +66,18 @@ public class HaloPluginManager extends DefaultPluginManager implements SpringPlu // components before properties set. } + @Override + public void afterPropertiesSet() throws Exception { + super.runtimeMode = pluginProperties.getRuntimeMode(); + this.sharedContext = Lazy.of(() -> SharedApplicationContextFactory.create(rootContext)); + setExactVersionAllowed(pluginProperties.isExactVersionAllowed()); + setSystemVersion(systemVersionSupplier.get().toStableVersion().toString()); + + super.initialize(); + // the listener must be after the super#initialize + addPluginStateListener(new PluginStartedListener()); + } + @Override protected ExtensionFactory createExtensionFactory() { return new SpringExtensionFactory(this); @@ -154,6 +161,10 @@ public class HaloPluginManager extends DefaultPluginManager implements SpringPlu @Override public List getDependents(String pluginId) { + if (getPlugin(pluginId) == null) { + return List.of(); + } + var dependents = new ArrayList(); var stack = new Stack(); dependencyResolver.getDependents(pluginId).forEach(stack::push); diff --git a/application/src/test/java/run/halo/app/plugin/HaloPluginManagerTest.java b/application/src/test/java/run/halo/app/plugin/HaloPluginManagerTest.java new file mode 100644 index 000000000..d6711e1ab --- /dev/null +++ b/application/src/test/java/run/halo/app/plugin/HaloPluginManagerTest.java @@ -0,0 +1,63 @@ +package run.halo.app.plugin; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + +import com.github.zafarkhaja.semver.Version; +import java.nio.file.Path; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.pf4j.RuntimeMode; +import org.springframework.context.ApplicationContext; +import run.halo.app.infra.SystemVersionSupplier; + +@ExtendWith(MockitoExtension.class) +class HaloPluginManagerTest { + + @Mock + PluginProperties pluginProperties; + + @Mock + SystemVersionSupplier systemVersionSupplier; + + @Mock + PluginsRootGetter pluginsRootGetter; + + @Mock + ApplicationContext rootContext; + + @InjectMocks + HaloPluginManager pluginManager; + + @TempDir + Path tempDir; + + @Test + void shouldGetDependentsWhilePluginsNotResolved() throws Exception { + when(pluginProperties.getRuntimeMode()).thenReturn(RuntimeMode.DEPLOYMENT); + when(systemVersionSupplier.get()).thenReturn(Version.of(1, 2, 3)); + when(pluginsRootGetter.get()).thenReturn(tempDir); + pluginManager.afterPropertiesSet(); + // if we don't invoke resolves + var dependents = pluginManager.getDependents("fake-plugin"); + assertTrue(dependents.isEmpty()); + } + + @Test + void shouldGetDependentsWhilePluginsResolved() throws Exception { + when(pluginProperties.getRuntimeMode()).thenReturn(RuntimeMode.DEPLOYMENT); + when(systemVersionSupplier.get()).thenReturn(Version.of(1, 2, 3)); + when(pluginsRootGetter.get()).thenReturn(tempDir); + pluginManager.afterPropertiesSet(); + pluginManager.loadPlugins(); + // if we don't invoke resolves + var dependents = pluginManager.getDependents("fake-plugin"); + assertTrue(dependents.isEmpty()); + } + + +}