From f6ede83be37a29b069a602fdf4b4864c16f2c3d2 Mon Sep 17 00:00:00 2001 From: rreich Date: Thu, 5 Nov 2020 14:37:08 +0100 Subject: [PATCH] Support multiple plugin root directories (#404) --- .../java/org/pf4j/AbstractPluginManager.java | 65 +++++++++++----- .../java/org/pf4j/BasePluginRepository.java | 46 ++++++------ .../java/org/pf4j/DefaultPluginManager.java | 21 ++++-- .../org/pf4j/DefaultPluginRepository.java | 31 +++++--- .../org/pf4j/DevelopmentPluginRepository.java | 10 ++- .../main/java/org/pf4j/JarPluginManager.java | 8 +- .../java/org/pf4j/JarPluginRepository.java | 10 ++- .../src/main/java/org/pf4j/PluginManager.java | 12 ++- .../main/java/org/pf4j/ZipPluginManager.java | 4 +- .../org/pf4j/DefaultPluginRepositoryTest.java | 59 ++++++++++----- .../LoadPluginsFromMultipleRootsTest.java | 75 +++++++++++++++++++ .../test/java/org/pf4j/LoadPluginsTest.java | 6 ++ 12 files changed, 258 insertions(+), 89 deletions(-) create mode 100644 pf4j/src/test/java/org/pf4j/LoadPluginsFromMultipleRootsTest.java diff --git a/pf4j/src/main/java/org/pf4j/AbstractPluginManager.java b/pf4j/src/main/java/org/pf4j/AbstractPluginManager.java index 3d109e2..9562257 100644 --- a/pf4j/src/main/java/org/pf4j/AbstractPluginManager.java +++ b/pf4j/src/main/java/org/pf4j/AbstractPluginManager.java @@ -25,12 +25,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * This class implements the boilerplate plugin code that any {@link PluginManager} @@ -51,7 +53,7 @@ public abstract class AbstractPluginManager implements PluginManager { public static final String DEFAULT_PLUGINS_DIR = "plugins"; public static final String DEVELOPMENT_PLUGINS_DIR = "../plugins"; - protected Path pluginsRoot; + protected final List pluginsRoots = new ArrayList<>(); protected ExtensionFinder extensionFinder; @@ -109,19 +111,28 @@ public abstract class AbstractPluginManager implements PluginManager { protected VersionManager versionManager; /** - * The plugins root is supplied by {@code System.getProperty("pf4j.pluginsDir", "plugins")}. + * The plugins roots are supplied as comma-separated list by {@code System.getProperty("pf4j.pluginsDir", "plugins")}. */ public AbstractPluginManager() { initialize(); } /** - * Constructs {@code AbstractPluginManager} with the given plugins root. + * Constructs {@code AbstractPluginManager} with the given plugins roots. * - * @param pluginsRoot the root to search for plugins + * @param pluginsRoots the roots to search for plugins */ - public AbstractPluginManager(Path pluginsRoot) { - this.pluginsRoot = pluginsRoot; + public AbstractPluginManager(Path... pluginsRoots) { + this(Arrays.asList(pluginsRoots)); + } + + /** + * Constructs {@code AbstractPluginManager} with the given plugins roots. + * + * @param pluginsRoots the roots to search for plugins + */ + public AbstractPluginManager(List pluginsRoots) { + this.pluginsRoots.addAll(pluginsRoots); initialize(); } @@ -200,12 +211,17 @@ public abstract class AbstractPluginManager implements PluginManager { */ @Override public void loadPlugins() { - log.debug("Lookup plugins in '{}'", pluginsRoot); - // check for plugins root - if (Files.notExists(pluginsRoot) || !Files.isDirectory(pluginsRoot)) { - log.warn("No '{}' root", pluginsRoot); + log.debug("Lookup plugins in '{}'", pluginsRoots); + // check for plugins roots + if (pluginsRoots.isEmpty()) { + log.warn("No plugins roots configured"); return; } + pluginsRoots.forEach(path -> { + if (Files.notExists(path) || !Files.isDirectory(path)) { + log.warn("No '{}' root", path); + } + }); // get all plugin paths from repository List pluginPaths = pluginRepository.getPluginPaths(); @@ -599,8 +615,15 @@ public abstract class AbstractPluginManager implements PluginManager { return pluginLoader; } + @Override public Path getPluginsRoot() { - return pluginsRoot; + return pluginsRoots.stream() + .findFirst() + .orElseThrow(() -> new IllegalStateException("pluginsRoots have not been initialized, yet.")); + } + + public List getPluginsRoots() { + return Collections.unmodifiableList(pluginsRoots); } @Override @@ -687,8 +710,8 @@ public abstract class AbstractPluginManager implements PluginManager { pluginStateListeners = new ArrayList<>(); - if (pluginsRoot == null) { - pluginsRoot = createPluginsRoot(); + if (pluginsRoots.isEmpty()) { + pluginsRoots.addAll(createPluginsRoot()); } pluginRepository = createPluginRepository(); @@ -704,20 +727,24 @@ public abstract class AbstractPluginManager implements PluginManager { } /** - * Add the possibility to override the plugins root. - * If a {@link #PLUGINS_DIR_PROPERTY_NAME} system property is defined than this method returns that root. + * Add the possibility to override the plugins roots. + * If a {@link #PLUGINS_DIR_PROPERTY_NAME} system property is defined than this method returns that roots. * If {@link #getRuntimeMode()} returns {@link RuntimeMode#DEVELOPMENT} than {@link #DEVELOPMENT_PLUGINS_DIR} * is returned else this method returns {@link #DEFAULT_PLUGINS_DIR}. * * @return the plugins root */ - protected Path createPluginsRoot() { + protected List createPluginsRoot() { String pluginsDir = System.getProperty(PLUGINS_DIR_PROPERTY_NAME); - if (pluginsDir == null) { - pluginsDir = isDevelopment() ? DEVELOPMENT_PLUGINS_DIR : DEFAULT_PLUGINS_DIR; + if (pluginsDir != null && !pluginsDir.isEmpty()) { + return Arrays.stream(pluginsDir.split(",")) + .map(String::trim) + .map(Paths::get) + .collect(Collectors.toList()); } - return Paths.get(pluginsDir); + pluginsDir = isDevelopment() ? DEVELOPMENT_PLUGINS_DIR : DEFAULT_PLUGINS_DIR; + return Collections.singletonList(Paths.get(pluginsDir)); } /** diff --git a/pf4j/src/main/java/org/pf4j/BasePluginRepository.java b/pf4j/src/main/java/org/pf4j/BasePluginRepository.java index ea5ad3b..9ab8f96 100644 --- a/pf4j/src/main/java/org/pf4j/BasePluginRepository.java +++ b/pf4j/src/main/java/org/pf4j/BasePluginRepository.java @@ -22,11 +22,11 @@ import java.io.FileFilter; import java.io.IOException; import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * @author Decebal Suiu @@ -34,17 +34,21 @@ import java.util.List; */ public class BasePluginRepository implements PluginRepository { - protected final Path pluginsRoot; + protected final List pluginsRoots; protected FileFilter filter; protected Comparator comparator; - public BasePluginRepository(Path pluginsRoot) { - this(pluginsRoot, null); + public BasePluginRepository(Path... pluginsRoots) { + this(Arrays.asList(pluginsRoots)); } - public BasePluginRepository(Path pluginsRoot, FileFilter filter) { - this.pluginsRoot = pluginsRoot; + public BasePluginRepository(List pluginsRoots) { + this(pluginsRoots, null); + } + + public BasePluginRepository(List pluginsRoots, FileFilter filter) { + this.pluginsRoots = pluginsRoots; this.filter = filter; // last modified file is first @@ -67,22 +71,11 @@ public class BasePluginRepository implements PluginRepository { @Override public List getPluginPaths() { - File[] files = pluginsRoot.toFile().listFiles(filter); - - if ((files == null) || files.length == 0) { - return Collections.emptyList(); - } - - if (comparator != null) { - Arrays.sort(files, comparator); - } - - List paths = new ArrayList<>(files.length); - for (File file : files) { - paths.add(file.toPath()); - } - - return paths; + return pluginsRoots.stream() + .flatMap(path -> streamFiles(path, filter)) + .sorted(comparator) + .map(File::toPath) + .collect(Collectors.toList()); } @Override @@ -101,4 +94,11 @@ public class BasePluginRepository implements PluginRepository { } } + protected Stream streamFiles(Path directory, FileFilter filter) { + File[] files = directory.toFile().listFiles(filter); + return files != null + ? Arrays.stream(files) + : Stream.empty(); + } + } diff --git a/pf4j/src/main/java/org/pf4j/DefaultPluginManager.java b/pf4j/src/main/java/org/pf4j/DefaultPluginManager.java index 9cad187..e2667d4 100644 --- a/pf4j/src/main/java/org/pf4j/DefaultPluginManager.java +++ b/pf4j/src/main/java/org/pf4j/DefaultPluginManager.java @@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; /** * Default implementation of the {@link PluginManager} interface. @@ -41,8 +42,12 @@ public class DefaultPluginManager extends AbstractPluginManager { super(); } - public DefaultPluginManager(Path pluginsRoot) { - super(pluginsRoot); + public DefaultPluginManager(Path... pluginsRoots) { + super(pluginsRoots); + } + + public DefaultPluginManager(List pluginsRoots) { + super(pluginsRoots); } @Override @@ -73,7 +78,11 @@ public class DefaultPluginManager extends AbstractPluginManager { @Override protected PluginStatusProvider createPluginStatusProvider() { String configDir = System.getProperty(PLUGINS_DIR_CONFIG_PROPERTY_NAME); - Path configPath = configDir != null ? Paths.get(configDir) : getPluginsRoot(); + Path configPath = configDir != null + ? Paths.get(configDir) + : getPluginsRoots().stream() + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("No pluginsRoot configured")); return new DefaultPluginStatusProvider(configPath); } @@ -81,9 +90,9 @@ public class DefaultPluginManager extends AbstractPluginManager { @Override protected PluginRepository createPluginRepository() { return new CompoundPluginRepository() - .add(new DevelopmentPluginRepository(getPluginsRoot()), this::isDevelopment) - .add(new JarPluginRepository(getPluginsRoot()), this::isNotDevelopment) - .add(new DefaultPluginRepository(getPluginsRoot()), this::isNotDevelopment); + .add(new DevelopmentPluginRepository(getPluginsRoots()), this::isDevelopment) + .add(new JarPluginRepository(getPluginsRoots()), this::isNotDevelopment) + .add(new DefaultPluginRepository(getPluginsRoots()), this::isNotDevelopment); } @Override diff --git a/pf4j/src/main/java/org/pf4j/DefaultPluginRepository.java b/pf4j/src/main/java/org/pf4j/DefaultPluginRepository.java index 2fafbc7..82a447f 100644 --- a/pf4j/src/main/java/org/pf4j/DefaultPluginRepository.java +++ b/pf4j/src/main/java/org/pf4j/DefaultPluginRepository.java @@ -29,6 +29,7 @@ import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.nio.file.Path; +import java.util.Arrays; import java.util.List; /** @@ -38,8 +39,12 @@ public class DefaultPluginRepository extends BasePluginRepository { private static final Logger log = LoggerFactory.getLogger(DefaultPluginRepository.class); - public DefaultPluginRepository(Path pluginsRoot) { - super(pluginsRoot); + public DefaultPluginRepository(Path... pluginsRoots) { + this(Arrays.asList(pluginsRoots)); + } + + public DefaultPluginRepository(List pluginsRoots) { + super(pluginsRoots); AndFileFilter pluginsFilter = new AndFileFilter(new DirectoryFileFilter()); pluginsFilter.addFileFilter(new NotFileFilter(createHiddenPluginFilter())); @@ -64,16 +69,18 @@ public class DefaultPluginRepository extends BasePluginRepository { private void extractZipFiles() { // expand plugins zip files - File[] zipFiles = pluginsRoot.toFile().listFiles(new ZipFileFilter()); - if ((zipFiles != null) && zipFiles.length > 0) { - for (File pluginZip : zipFiles) { - try { - FileUtils.expandIfZip(pluginZip.toPath()); - } catch (IOException e) { - log.error("Cannot expand plugin zip '{}'", pluginZip); - log.error(e.getMessage(), e); - } - } + pluginsRoots.stream() + .flatMap(path -> streamFiles(path, new ZipFileFilter())) + .map(File::toPath) + .forEach(this::expandIfZip); + } + + private void expandIfZip(Path filePath) { + try { + FileUtils.expandIfZip(filePath); + } catch (IOException e) { + log.error("Cannot expand plugin zip '{}'", filePath); + log.error(e.getMessage(), e); } } diff --git a/pf4j/src/main/java/org/pf4j/DevelopmentPluginRepository.java b/pf4j/src/main/java/org/pf4j/DevelopmentPluginRepository.java index e8f2c69..fdc74c9 100644 --- a/pf4j/src/main/java/org/pf4j/DevelopmentPluginRepository.java +++ b/pf4j/src/main/java/org/pf4j/DevelopmentPluginRepository.java @@ -24,6 +24,8 @@ import org.pf4j.util.OrFileFilter; import java.io.FileFilter; import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; /** * @author Decebal Suiu @@ -33,8 +35,12 @@ public class DevelopmentPluginRepository extends BasePluginRepository { public static final String MAVEN_BUILD_DIR = "target"; public static final String GRADLE_BUILD_DIR = "build"; - public DevelopmentPluginRepository(Path pluginsRoot) { - super(pluginsRoot); + public DevelopmentPluginRepository(Path... pluginsRoots) { + this(Arrays.asList(pluginsRoots)); + } + + public DevelopmentPluginRepository(List pluginsRoots) { + super(pluginsRoots); AndFileFilter pluginsFilter = new AndFileFilter(new DirectoryFileFilter()); pluginsFilter.addFileFilter(new NotFileFilter(createHiddenPluginFilter())); diff --git a/pf4j/src/main/java/org/pf4j/JarPluginManager.java b/pf4j/src/main/java/org/pf4j/JarPluginManager.java index f280466..ebbc63d 100644 --- a/pf4j/src/main/java/org/pf4j/JarPluginManager.java +++ b/pf4j/src/main/java/org/pf4j/JarPluginManager.java @@ -30,8 +30,8 @@ public class JarPluginManager extends DefaultPluginManager { super(); } - public JarPluginManager(Path pluginsRoot) { - super(pluginsRoot); + public JarPluginManager(Path... pluginsRoots) { + super(pluginsRoots); } @Override @@ -49,8 +49,8 @@ public class JarPluginManager extends DefaultPluginManager { @Override protected PluginRepository createPluginRepository() { return new CompoundPluginRepository() - .add(new DevelopmentPluginRepository(getPluginsRoot()), this::isDevelopment) - .add(new JarPluginRepository(getPluginsRoot()), this::isNotDevelopment); + .add(new DevelopmentPluginRepository(getPluginsRoots()), this::isDevelopment) + .add(new JarPluginRepository(getPluginsRoots()), this::isNotDevelopment); } } diff --git a/pf4j/src/main/java/org/pf4j/JarPluginRepository.java b/pf4j/src/main/java/org/pf4j/JarPluginRepository.java index a8be3ff..d629bbd 100644 --- a/pf4j/src/main/java/org/pf4j/JarPluginRepository.java +++ b/pf4j/src/main/java/org/pf4j/JarPluginRepository.java @@ -18,14 +18,20 @@ package org.pf4j; import org.pf4j.util.JarFileFilter; import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; /** * @author Decebal Suiu */ public class JarPluginRepository extends BasePluginRepository { - public JarPluginRepository(Path pluginsRoot) { - super(pluginsRoot, new JarFileFilter()); + public JarPluginRepository(Path... pluginsRoots) { + this(Arrays.asList(pluginsRoots)); + } + + public JarPluginRepository(List pluginsRoots) { + super(pluginsRoots, new JarFileFilter()); } } diff --git a/pf4j/src/main/java/org/pf4j/PluginManager.java b/pf4j/src/main/java/org/pf4j/PluginManager.java index 248b1ac..b717656 100644 --- a/pf4j/src/main/java/org/pf4j/PluginManager.java +++ b/pf4j/src/main/java/org/pf4j/PluginManager.java @@ -205,12 +205,22 @@ public interface PluginManager { String getSystemVersion(); /** - * Gets the path of the folder where plugins are installed. + * Gets the first path of the folders where plugins are installed. + * + * @deprecated Use {@link #getPluginsRoots()} instead to get all paths where plugins are could be installed. * * @return Path of plugins root */ + @Deprecated Path getPluginsRoot(); + /** + * Gets the a read-only list of all paths of the folders where plugins are installed. + * + * @return Paths of plugins roots + */ + List getPluginsRoots(); + VersionManager getVersionManager(); } diff --git a/pf4j/src/main/java/org/pf4j/ZipPluginManager.java b/pf4j/src/main/java/org/pf4j/ZipPluginManager.java index a32d156..a22f3c6 100644 --- a/pf4j/src/main/java/org/pf4j/ZipPluginManager.java +++ b/pf4j/src/main/java/org/pf4j/ZipPluginManager.java @@ -42,8 +42,8 @@ public class ZipPluginManager extends DefaultPluginManager { @Override protected PluginRepository createPluginRepository() { return new CompoundPluginRepository() - .add(new DevelopmentPluginRepository(getPluginsRoot()), this::isDevelopment) - .add(new DefaultPluginRepository(getPluginsRoot()), this::isNotDevelopment); + .add(new DevelopmentPluginRepository(getPluginsRoots()), this::isDevelopment) + .add(new DefaultPluginRepository(getPluginsRoots()), this::isNotDevelopment); } } diff --git a/pf4j/src/test/java/org/pf4j/DefaultPluginRepositoryTest.java b/pf4j/src/test/java/org/pf4j/DefaultPluginRepositoryTest.java index 3e31811..b8ffd7c 100644 --- a/pf4j/src/test/java/org/pf4j/DefaultPluginRepositoryTest.java +++ b/pf4j/src/test/java/org/pf4j/DefaultPluginRepositoryTest.java @@ -15,10 +15,11 @@ */ package org.pf4j; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; import org.pf4j.plugin.PluginZip; +import org.pf4j.util.FileUtils; import java.io.IOException; import java.nio.file.Files; @@ -35,18 +36,40 @@ import static org.junit.jupiter.api.Assertions.assertTrue; */ public class DefaultPluginRepositoryTest { - @TempDir - Path pluginsPath; + Path pluginsPath1; + Path pluginsPath2; @BeforeEach public void setUp() throws IOException { - Path plugin1Path = Files.createDirectory(pluginsPath.resolve("plugin-1")); + pluginsPath1 = Files.createTempDirectory("junit-pf4j-"); + pluginsPath2 = Files.createTempDirectory("junit-pf4j-"); + Path plugin1Path = Files.createDirectory(pluginsPath1.resolve("plugin-1")); // Prove that we can delete a folder with a file inside Files.createFile(plugin1Path.resolve("myfile")); // Create a zip file for plugin-1 to test that it is deleted when plugin is deleted - new PluginZip.Builder(pluginsPath.resolve("plugin-1.zip"), "plugin-1").pluginVersion("1.0").build(); - Files.createDirectory(pluginsPath.resolve("plugin-2")); - Files.createDirectory(pluginsPath.resolve("plugin-3")); + new PluginZip.Builder(pluginsPath1.resolve("plugin-1.zip"), "plugin-1").pluginVersion("1.0").build(); + Files.createDirectory(pluginsPath2.resolve("plugin-2")); + Files.createDirectory(pluginsPath2.resolve("plugin-3")); + } + + @AfterEach + public void tearDown() throws IOException { + FileUtils.delete(pluginsPath1); + FileUtils.delete(pluginsPath2); + } + + /** + * Test of {@link DefaultPluginRepository#getPluginPaths()} method. + */ + @Test + public void testGetPluginArchivesFromSinglePath() { + PluginRepository repository = new DefaultPluginRepository(pluginsPath2); + + List pluginPaths = repository.getPluginPaths(); + + assertEquals(2, pluginPaths.size()); + assertPathExists(pluginPaths, pluginsPath2.resolve("plugin-2")); + assertPathExists(pluginPaths, pluginsPath2.resolve("plugin-3")); } /** @@ -54,14 +77,14 @@ public class DefaultPluginRepositoryTest { */ @Test public void testGetPluginArchives() { - PluginRepository repository = new DefaultPluginRepository(pluginsPath); + PluginRepository repository = new DefaultPluginRepository(pluginsPath1, pluginsPath2); List pluginPaths = repository.getPluginPaths(); assertEquals(3, pluginPaths.size()); - assertPathExists(pluginPaths, pluginsPath.resolve("plugin-1")); - assertPathExists(pluginPaths, pluginsPath.resolve("plugin-2")); - assertPathExists(pluginPaths, pluginsPath.resolve("plugin-3")); + assertPathExists(pluginPaths, pluginsPath1.resolve("plugin-1")); + assertPathExists(pluginPaths, pluginsPath2.resolve("plugin-2")); + assertPathExists(pluginPaths, pluginsPath2.resolve("plugin-3")); } /** @@ -69,18 +92,18 @@ public class DefaultPluginRepositoryTest { */ @Test public void testDeletePluginPath() { - PluginRepository repository = new DefaultPluginRepository(pluginsPath); + PluginRepository repository = new DefaultPluginRepository(pluginsPath1, pluginsPath2); - assertTrue(Files.exists(pluginsPath.resolve("plugin-1.zip"))); - assertTrue(repository.deletePluginPath(pluginsPath.resolve("plugin-1"))); - assertFalse(Files.exists(pluginsPath.resolve("plugin-1.zip"))); - assertTrue(repository.deletePluginPath(pluginsPath.resolve("plugin-3"))); - assertFalse(repository.deletePluginPath(pluginsPath.resolve("plugin-4"))); + assertTrue(Files.exists(pluginsPath1.resolve("plugin-1.zip"))); + assertTrue(repository.deletePluginPath(pluginsPath1.resolve("plugin-1"))); + assertFalse(Files.exists(pluginsPath1.resolve("plugin-1.zip"))); + assertTrue(repository.deletePluginPath(pluginsPath2.resolve("plugin-3"))); + assertFalse(repository.deletePluginPath(pluginsPath2.resolve("plugin-4"))); List pluginPaths = repository.getPluginPaths(); assertEquals(1, pluginPaths.size()); - assertEquals(pluginsPath.relativize(pluginPaths.get(0)).toString(), "plugin-2"); + assertEquals(pluginsPath2.relativize(pluginPaths.get(0)).toString(), "plugin-2"); } private void assertPathExists(List paths, Path path) { diff --git a/pf4j/src/test/java/org/pf4j/LoadPluginsFromMultipleRootsTest.java b/pf4j/src/test/java/org/pf4j/LoadPluginsFromMultipleRootsTest.java new file mode 100644 index 0000000..2117a62 --- /dev/null +++ b/pf4j/src/test/java/org/pf4j/LoadPluginsFromMultipleRootsTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pf4j; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.pf4j.plugin.PluginZip; +import org.pf4j.util.FileUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class LoadPluginsFromMultipleRootsTest { + + private DefaultPluginManager pluginManager; + + Path pluginsPath1; + Path pluginsPath2; + + @BeforeEach + public void setUp() throws IOException { + pluginsPath1 = Files.createTempDirectory("junit-pf4j-"); + pluginsPath2 = Files.createTempDirectory("junit-pf4j-"); + pluginManager = new DefaultPluginManager(pluginsPath1, pluginsPath2); + } + + @AfterEach + public void tearDown() throws IOException { + FileUtils.delete(pluginsPath1); + FileUtils.delete(pluginsPath2); + } + + @Test + public void load() throws Exception { + PluginZip pluginZip1 = new PluginZip.Builder(pluginsPath1.resolve("my-plugin-1.2.3.zip"), "myPlugin") + .pluginVersion("1.2.3") + .build(); + + PluginZip pluginZip2 = new PluginZip.Builder(pluginsPath2.resolve("my-other-plugin-4.5.6.zip"), "myOtherPlugin") + .pluginVersion("4.5.6") + .build(); + + assertTrue(Files.exists(pluginZip1.path())); + assertEquals(0, pluginManager.getPlugins().size()); + + pluginManager.loadPlugins(); + + assertTrue(Files.exists(pluginZip1.path())); + assertTrue(Files.exists(pluginZip1.unzippedPath())); + assertTrue(Files.exists(pluginZip2.path())); + assertTrue(Files.exists(pluginZip2.unzippedPath())); + assertEquals(2, pluginManager.getPlugins().size()); + assertEquals(pluginZip1.pluginId(), pluginManager.idForPath(pluginZip1.unzippedPath())); + assertEquals(pluginZip2.pluginId(), pluginManager.idForPath(pluginZip2.unzippedPath())); + } + +} diff --git a/pf4j/src/test/java/org/pf4j/LoadPluginsTest.java b/pf4j/src/test/java/org/pf4j/LoadPluginsTest.java index e3dac02..ef2376b 100644 --- a/pf4j/src/test/java/org/pf4j/LoadPluginsTest.java +++ b/pf4j/src/test/java/org/pf4j/LoadPluginsTest.java @@ -23,6 +23,7 @@ import org.pf4j.plugin.PluginZip; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; @@ -200,6 +201,11 @@ public class LoadPluginsTest { assertEquals(pluginsPath, pluginManager.getPluginsRoot()); } + @Test + public void getRoots() { + assertEquals(Collections.singletonList(pluginsPath), pluginManager.getPluginsRoots()); + } + @Test public void notAPlugin() { pluginsPath.resolve("not-a-zip"); -- 2.39.5