Browse Source

Fix #576 (#579)

pull/570/head
Decebal Suiu 5 months ago committed by GitHub
parent
commit
d4df01f414
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 25
      pf4j/src/main/java/org/pf4j/AbstractPluginManager.java
  2. 47
      pf4j/src/test/java/org/pf4j/AbstractPluginManagerTest.java
  3. 36
      pf4j/src/test/java/org/pf4j/DefaultPluginManagerTest.java

25
pf4j/src/main/java/org/pf4j/AbstractPluginManager.java

@ -282,11 +282,23 @@ public abstract class AbstractPluginManager implements PluginManager {
* @return true if the plugin was unloaded, otherwise false
*/
protected boolean unloadPlugin(String pluginId, boolean unloadDependents) {
return unloadPlugin(pluginId, unloadDependents, true);
}
/**
* Unload the specified plugin and it's dependents.
*
* @param pluginId the pluginId of the plugin to unload
* @param unloadDependents if true, unload dependents
* @param resolveDependencies if true, resolve dependencies
* @return true if the plugin was unloaded, otherwise false
*/
protected boolean unloadPlugin(String pluginId, boolean unloadDependents, boolean resolveDependencies) {
if (unloadDependents) {
List<String> dependents = dependencyResolver.getDependents(pluginId);
while (!dependents.isEmpty()) {
String dependent = dependents.remove(0);
unloadPlugin(dependent, false);
unloadPlugin(dependent, false, false);
dependents.addAll(0, dependencyResolver.getDependents(dependent));
}
}
@ -331,6 +343,11 @@ public abstract class AbstractPluginManager implements PluginManager {
}
}
// resolve the plugins again (update plugins graph)
if (resolveDependencies) {
resolveDependencies();
}
return true;
}
@ -917,7 +934,7 @@ public abstract class AbstractPluginManager implements PluginManager {
pluginId = pluginDescriptor.getPluginId();
// add plugin to the list with plugins
plugins.put(pluginId, pluginWrapper);
addPlugin(pluginWrapper);
getUnresolvedPlugins().add(pluginWrapper);
// add plugin class loader to the list with class loaders
@ -1114,6 +1131,10 @@ public abstract class AbstractPluginManager implements PluginManager {
this.resolveRecoveryStrategy = resolveRecoveryStrategy;
}
void addPlugin(PluginWrapper pluginWrapper) {
plugins.put(pluginWrapper.getPluginId(), pluginWrapper);
}
/**
* Strategy for handling the recovery of a plugin that could not be resolved
* (loaded) due to a dependency problem.

47
pf4j/src/test/java/org/pf4j/AbstractPluginManagerTest.java

@ -36,6 +36,8 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
@ -49,7 +51,7 @@ public class AbstractPluginManagerTest {
@BeforeEach
void setUp() {
pluginManager = mock(AbstractPluginManager.class, withSettings()
pluginManager = mock(AbstractPluginManagerWithDefaultVersionManager.class, withSettings()
.useConstructor()
.defaultAnswer(CALLS_REAL_METHODS));
}
@ -119,11 +121,33 @@ public class AbstractPluginManagerTest {
assertThrows(PluginNotFoundException.class, () -> pluginManager.checkPluginId("plugin1"));
}
private PluginWrapper createPluginWrapper(String pluginId) {
DefaultPluginDescriptor pluginDescriptor = new DefaultPluginDescriptor();
pluginDescriptor.setPluginId(pluginId);
pluginDescriptor.setPluginVersion("1.2.3");
@Test
void unloadPluginCallsResolveDependenciesOnce() {
PluginWrapper pluginWrapper1 = createPluginWrapper("plugin1", "plugin2");
PluginWrapper pluginWrapper2 = createPluginWrapper("plugin2");
pluginManager.addPlugin(pluginWrapper1);
pluginManager.addPlugin(pluginWrapper2);
pluginManager.resolveDependencies();
// reset the mock to not count the explicit call of resolveDependencies
reset(pluginManager);
pluginManager.unloadPlugin("plugin2", true);
verify(pluginManager, times(1)).resolveDependencies();
}
private PluginWrapper createPluginWrapper(String pluginId, String... dependencies) {
PluginDescriptor pluginDescriptor = new DefaultPluginDescriptor()
.setPluginId(pluginId)
.setPluginVersion("1.2.3")
.setDependencies(String.join(", ", dependencies));
return createPluginWrapper(pluginDescriptor);
}
private PluginWrapper createPluginWrapper(PluginDescriptor pluginDescriptor) {
PluginWrapper pluginWrapper = new PluginWrapper(pluginManager, pluginDescriptor, Paths.get("plugin1"), getClass().getClassLoader());
Plugin plugin = mock(Plugin.class);
pluginWrapper.setPluginFactory(wrapper -> plugin);
@ -131,4 +155,17 @@ public class AbstractPluginManagerTest {
return pluginWrapper;
}
static abstract class AbstractPluginManagerWithDefaultVersionManager extends AbstractPluginManager {
public AbstractPluginManagerWithDefaultVersionManager() {
super();
}
@Override
protected VersionManager createVersionManager() {
return new DefaultVersionManager();
}
}
}

36
pf4j/src/test/java/org/pf4j/DefaultPluginManagerTest.java

@ -396,4 +396,40 @@ public class DefaultPluginManagerTest {
assertThrows(PluginNotFoundException.class, () -> pluginManager.stopPlugin(pluginZip2.pluginId()));
}
@Test
void deletePluginWithDependency() throws IOException {
PluginZip pluginZip1 = new PluginZip.Builder(pluginsPath.resolve("my-first-plugin-1.1.1.zip"), "myPlugin1")
.pluginVersion("1.1.1")
.build();
PluginZip pluginZip2 = new PluginZip.Builder(pluginsPath.resolve("my-second-plugin-2.2.2.zip"), "myPlugin2")
.pluginVersion("2.2.2")
.pluginDependencies("myPlugin1")
.build();
PluginZip pluginZip3 = new PluginZip.Builder(pluginsPath.resolve("my-third-plugin-3.3.3.zip"), "myPlugin3")
.pluginVersion("3.3.3")
.pluginDependencies("myPlugin2")
.build();
pluginManager.loadPlugins();
pluginManager.startPlugins();
assertEquals(PluginState.STARTED, pluginManager.getPlugin(pluginZip1.pluginId()).getPluginState());
assertEquals(PluginState.STARTED, pluginManager.getPlugin(pluginZip2.pluginId()).getPluginState());
assertEquals(PluginState.STARTED, pluginManager.getPlugin(pluginZip3.pluginId()).getPluginState());
System.out.println("Stopping " + pluginZip2.pluginId());
pluginManager.stopPlugin(pluginZip2.pluginId());
assertEquals(PluginState.STOPPED, pluginManager.getPlugin(pluginZip2.pluginId()).getPluginState());
boolean deleted = pluginManager.deletePlugin(pluginZip2.pluginId());
assertTrue(deleted);
assertEquals(1, pluginManager.getPlugins().size()); // myPlugin1 should still be there, myPlugin2 and myPlugin3 should be gone
pluginManager.stopPlugin(pluginZip1.pluginId());
assertEquals(PluginState.STOPPED, pluginManager.getPlugin(pluginZip1.pluginId()).getPluginState());
}
}

Loading…
Cancel
Save