Browse Source

Check no plugin with same pluginId is loaded (#287)

tags/release-3.0.0
Dmitry Timofeev 5 years ago
parent
commit
cd8e12c0bc

+ 20
- 0
pf4j/pom.xml View File

@@ -60,6 +60,26 @@
<version>${asm.version}</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<!-- An empty artifact, required while JUnit 4 is on the classpath to override its
dependency on hamcrest.

See http://hamcrest.org/JavaHamcrest/distributables#upgrading-from-hamcrest-1x
-->
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

+ 25
- 13
pf4j/src/main/java/org/pf4j/AbstractPluginManager.java View File

@@ -15,10 +15,6 @@
*/
package org.pf4j;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.pf4j.util.StringUtils;

import java.io.Closeable;
import java.io.IOException;
import java.nio.file.Files;
@@ -31,6 +27,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.pf4j.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This class implements the boilerplate plugin code that any {@link PluginManager}
@@ -51,17 +50,17 @@ public abstract class AbstractPluginManager implements PluginManager {

private PluginDescriptorFinder pluginDescriptorFinder;

/*
/**
* A map of plugins this manager is responsible for (the key is the 'pluginId').
*/
protected Map<String, PluginWrapper> plugins;

/*
/**
* A map of plugin class loaders (the key is the 'pluginId').
*/
private Map<String, ClassLoader> pluginClassLoaders;

/*
/**
* A list with unresolved plugins (unresolved dependency).
*/
private List<PluginWrapper> unresolvedPlugins;
@@ -71,23 +70,23 @@ public abstract class AbstractPluginManager implements PluginManager {
*/
private List<PluginWrapper> resolvedPlugins;

/*
/**
* A list with started plugins.
*/
private List<PluginWrapper> startedPlugins;

/*
/**
* The registered {@link PluginStateListener}s.
*/
private List<PluginStateListener> pluginStateListeners;

/*
/**
* Cache value for the runtime mode.
* No need to re-read it because it wont change at runtime.
*/
private RuntimeMode runtimeMode;

/*
/**
* The system version used for comparisons to the plugin requires attribute.
*/
private String systemVersion = "0.0.0";
@@ -822,18 +821,31 @@ public abstract class AbstractPluginManager implements PluginManager {
}

protected PluginWrapper loadPluginFromPath(Path pluginPath) throws PluginException {
// test for plugin duplication
// Test for plugin path duplication
String pluginId = idForPath(pluginPath);
if (pluginId != null) {
throw new PluginAlreadyLoadedException(pluginId, pluginPath);
}

// retrieves the plugin descriptor
// Retrieve and validate the plugin descriptor
PluginDescriptorFinder pluginDescriptorFinder = getPluginDescriptorFinder();
log.debug("Use '{}' to find plugins descriptors", pluginDescriptorFinder);
log.debug("Finding plugin descriptor for plugin '{}'", pluginPath);
PluginDescriptor pluginDescriptor = pluginDescriptorFinder.find(pluginPath);
validatePluginDescriptor(pluginDescriptor);

// Check there are no loaded plugins with the retrieved id
pluginId = pluginDescriptor.getPluginId();
if (plugins.containsKey(pluginId)) {
PluginWrapper loadedPlugin = getPlugin(pluginId);
throw new PluginException("There is an already loaded plugin ({}) "
+ "with the same id ({}) as the plugin at path '{}'. Simultaneous loading "
+ "of plugins with the same PluginId is not currently supported.\n"
+ "As a workaround you may include PluginVersion and PluginProvider "
+ "in PluginId.",
loadedPlugin, pluginId, pluginPath);
}

log.debug("Found descriptor {}", pluginDescriptor);
String pluginClassName = pluginDescriptor.getPluginClass();
log.debug("Class '{}' for plugin '{}'", pluginClassName, pluginPath);

+ 84
- 9
pf4j/src/test/java/org/pf4j/LoadPluginsTest.java View File

@@ -15,20 +15,26 @@
*/
package org.pf4j;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.pf4j.plugin.PluginZip;

import java.nio.file.Files;
import java.nio.file.Paths;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.pf4j.plugin.PluginZip;

public class LoadPluginsTest {

@@ -73,6 +79,75 @@ public class LoadPluginsTest {
assertNull(pluginManager.loadPluginFromPath(pluginZip.path()));
}

@Test
public void loadPluginWithSameIdDifferentPathFails() throws Exception {
String pluginId = "myPlugin";
String pluginVersion = "1.2.3";
File plugin1Path = pluginsFolder.newFile("my-plugin-1.2.3.zip");
PluginZip plugin1 = new PluginZip.Builder(plugin1Path, pluginId)
.pluginVersion(pluginVersion)
.build();

File plugin2Path = pluginsFolder.newFile("my-plugin-1.2.3-renamed.zip");
PluginZip plugin2 = new PluginZip.Builder(plugin2Path, pluginId)
.pluginVersion(pluginVersion)
.build();

// Verify the first plugin with the given id is loaded
assertNotNull(pluginManager.loadPluginFromPath(plugin1.path()));
Path loadedPlugin1Path = pluginManager.getPlugin(pluginId).getPluginPath();

try {
// Verify the second plugin is not loaded as it has the same metadata
pluginManager.loadPluginFromPath(plugin2.path());
fail("Expected loadPluginFromPath to fail");
} catch (PluginException e) {
// Check the path of the loaded plugin remains the same
PluginWrapper loadedPlugin = pluginManager.getPlugin(pluginId);
assertThat(loadedPlugin.getPluginPath(), equalTo(loadedPlugin1Path));
// Check the message includes relevant information
String message = e.getMessage();
assertThat(message, startsWith("There is an already loaded plugin"));
assertThat(message, containsString(pluginId));
assertThat(message, containsString("my-plugin-1.2.3-renamed"));
}
}

/**
* This test verifies the behaviour as of PF4J 2.x, where plugins of different
* versions but with the pluginId cannot be loaded correctly because the API
* uses pluginId as the unique identifier of the loaded plugin.
*/
@Test
public void loadPluginWithSameIdDifferentVersionsFails() throws Exception {
String pluginId = "myPlugin";
String plugin1Version = "1.2.3";
File plugin1Path = pluginsFolder.newFile("my-plugin-1.2.3.zip");
PluginZip plugin1 = new PluginZip.Builder(plugin1Path, pluginId)
.pluginVersion(plugin1Version)
.build();

String plugin2Version = "2.0.0";
File plugin2Path = pluginsFolder.newFile("my-plugin-2.0.0.zip");
PluginZip plugin2 = new PluginZip.Builder(plugin2Path, pluginId)
.pluginVersion(plugin2Version)
.build();

// Verify the first plugin with the given id is loaded
assertNotNull(pluginManager.loadPluginFromPath(plugin1.path()));
Path loadedPlugin1Path = pluginManager.getPlugin(pluginId).getPluginPath();
try {
// Verify the second plugin is not loaded as it has the same pluginId
pluginManager.loadPluginFromPath(plugin2.path());
fail("Expected loadPluginFromPath to fail");
} catch (PluginException e) {
// Check the path and version of the loaded plugin remain the same
PluginWrapper loadedPlugin = pluginManager.getPlugin(pluginId);
assertThat(loadedPlugin.getPluginPath(), equalTo(loadedPlugin1Path));
assertThat(loadedPlugin.getDescriptor().getVersion(), equalTo(plugin1Version));
}
}

@Test
public void loadUnloadLoad() throws Exception {
PluginZip pluginZip = new PluginZip.Builder(pluginsFolder.newFile("my-plugin-1.2.3.zip"), "myPlugin")

+ 1
- 0
pom.xml View File

@@ -48,6 +48,7 @@
<asm.version>7.0</asm.version>

<junit.version>4.12</junit.version>
<hamcrest.version>2.1</hamcrest.version>
<mockito.version>2.24.0</mockito.version>
<cobertura.version>2.7</cobertura.version>
<coveralls.version>3.1.0</coveralls.version>

Loading…
Cancel
Save