Browse Source

Add CompoundPluginDescriptorFinder (#172)

pull/175/head
Decebal Suiu 7 years ago committed by GitHub
parent
commit
1822cdede3
  1. 4
      pf4j/src/main/java/org/pf4j/AbstractPluginManager.java
  2. 81
      pf4j/src/main/java/org/pf4j/CompoundPluginDescriptorFinder.java
  3. 11
      pf4j/src/main/java/org/pf4j/DefaultExtensionFinder.java
  4. 64
      pf4j/src/main/java/org/pf4j/DefaultPluginDescriptorFinder.java
  5. 16
      pf4j/src/main/java/org/pf4j/DefaultPluginManager.java
  6. 23
      pf4j/src/main/java/org/pf4j/JarPluginManager.java
  7. 54
      pf4j/src/main/java/org/pf4j/ManifestPluginDescriptorFinder.java
  8. 13
      pf4j/src/main/java/org/pf4j/PluginDescriptorFinder.java
  9. 27
      pf4j/src/main/java/org/pf4j/PropertiesPluginDescriptorFinder.java
  10. 9
      pf4j/src/main/java/org/pf4j/ServiceProviderExtensionFinder.java
  11. 49
      pf4j/src/main/java/org/pf4j/util/FileUtils.java
  12. 104
      pf4j/src/test/java/org/pf4j/CompoundPluginDescriptorFinderTest.java
  13. 153
      pf4j/src/test/java/org/pf4j/LoadPluginsTest.java
  14. 8
      pf4j/src/test/java/org/pf4j/ManifestPluginDescriptorFinderTest.java
  15. 18
      pf4j/src/test/java/org/pf4j/PropertiesPluginDescriptorFinderTest.java
  16. 1
      pf4j/src/test/java/org/pf4j/plugin/AnotherFailTestPlugin.java
  17. 1
      pf4j/src/test/java/org/pf4j/plugin/FailTestPlugin.java
  18. 51
      pf4j/src/test/java/org/pf4j/plugin/MockPluginManager.java
  19. 107
      pf4j/src/test/java/org/pf4j/plugin/PluginZip.java
  20. 1
      pf4j/src/test/java/org/pf4j/plugin/TestPlugin.java
  21. 52
      pf4j/src/test/java/org/pf4j/util/FileUtilsTest.java

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

@ -780,8 +780,10 @@ public abstract class AbstractPluginManager implements PluginManager {
}
// retrieves the plugin descriptor
PluginDescriptorFinder pluginDescriptorFinder = getPluginDescriptorFinder();
log.debug("Use '{}' to find plugins descriptors", pluginDescriptorFinder);
log.debug("Finding plugin descriptor for plugin '{}'", pluginPath);
PluginDescriptor pluginDescriptor = getPluginDescriptorFinder().find(pluginPath);
PluginDescriptor pluginDescriptor = pluginDescriptorFinder.find(pluginPath);
validatePluginDescriptor(pluginDescriptor);
log.debug("Found descriptor {}", pluginDescriptor);
String pluginClassName = pluginDescriptor.getPluginClass();

81
pf4j/src/main/java/org/pf4j/CompoundPluginDescriptorFinder.java

@ -0,0 +1,81 @@
/*
* Copyright 2017 Decebal Suiu
*
* 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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
/**
* @author Decebal Suiu
*/
public class CompoundPluginDescriptorFinder implements PluginDescriptorFinder {
private static final Logger log = LoggerFactory.getLogger(CompoundPluginDescriptorFinder.class);
private List<PluginDescriptorFinder> finders = new ArrayList<>();
public CompoundPluginDescriptorFinder add(PluginDescriptorFinder finder) {
if (finder == null) {
throw new IllegalArgumentException("null not allowed");
}
finders.add(finder);
return this;
}
public int size() {
return finders.size();
}
@Override
public boolean isApplicable(Path pluginPath) {
for (PluginDescriptorFinder finder : finders) {
if (finder.isApplicable(pluginPath)) {
return true;
}
}
return false;
}
@Override
public PluginDescriptor find(Path pluginPath) throws PluginException {
for (PluginDescriptorFinder finder : finders) {
if (finder.isApplicable(pluginPath)) {
log.debug("'{}' is applicable for plugin '{}'", finder, pluginPath);
try {
PluginDescriptor pluginDescriptor = finder.find(pluginPath);
if (pluginDescriptor != null) {
return pluginDescriptor;
}
} catch (Exception e) {
// log the exception and continue with the next finder
log.error(e.getMessage()); // ?!
}
} else {
log.debug("'{}' is not applicable for plugin '{}'", finder, pluginPath);
}
}
throw new PluginException("No PluginDescriptorFinder for plugin '{}'", pluginPath);
}
}

11
pf4j/src/main/java/org/pf4j/DefaultExtensionFinder.java

@ -34,10 +34,8 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
public DefaultExtensionFinder(PluginManager pluginManager) {
this.pluginManager = pluginManager;
finders = new ArrayList<>();
addExtensionFinder(new LegacyExtensionFinder(pluginManager));
// addExtensionFinder(new ServiceProviderExtensionFinder(pluginManager));
add(new LegacyExtensionFinder(pluginManager));
// add(new ServiceProviderExtensionFinder(pluginManager));
}
@Override
@ -70,7 +68,6 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
return extensions;
}
@Override
public Set<String> findClassNames(String pluginId) {
Set<String> classNames = new HashSet<>();
@ -91,10 +88,10 @@ public class DefaultExtensionFinder implements ExtensionFinder, PluginStateListe
}
public DefaultExtensionFinder addServiceProviderExtensionFinder() {
return addExtensionFinder(new ServiceProviderExtensionFinder(pluginManager));
return add(new ServiceProviderExtensionFinder(pluginManager));
}
public DefaultExtensionFinder addExtensionFinder(ExtensionFinder finder) {
public DefaultExtensionFinder add(ExtensionFinder finder) {
finders.add(finder);
return this;

64
pf4j/src/main/java/org/pf4j/DefaultPluginDescriptorFinder.java

@ -1,64 +0,0 @@
/*
* Copyright 2013 Decebal Suiu
*
* 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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.jar.Manifest;
/**
* The default implementation for {@link PluginDescriptorFinder}.
* Now, this class it's a "link" to {@link ManifestPluginDescriptorFinder}.
*
* @author Decebal Suiu
*/
public class DefaultPluginDescriptorFinder extends ManifestPluginDescriptorFinder {
private static final Logger log = LoggerFactory.getLogger(ManifestPluginDescriptorFinder.class);
private PluginClasspath pluginClasspath;
public DefaultPluginDescriptorFinder(PluginClasspath pluginClasspath) {
this.pluginClasspath = pluginClasspath;
}
@Override
public Manifest readManifest(Path pluginPath) throws PluginException {
// TODO it's ok with first classes root? Another idea is to specify in PluginClasspath the folder.
if (pluginClasspath.getClassesDirectories().size() == 0) {
throw new PluginException("Failed to read manifest, no classes folder in classpath");
}
String classes = pluginClasspath.getClassesDirectories().get(0);
Path manifestPath = pluginPath.resolve(Paths.get(classes,"/META-INF/MANIFEST.MF"));
log.debug("Lookup plugin descriptor in '{}'", manifestPath);
if (Files.notExists(manifestPath)) {
throw new PluginException("Cannot find '{}' path", manifestPath);
}
try (InputStream input = Files.newInputStream(manifestPath)) {
return new Manifest(input);
} catch (IOException e) {
throw new PluginException(e.getMessage(), e);
}
}
}

16
pf4j/src/main/java/org/pf4j/DefaultPluginManager.java

@ -37,6 +37,11 @@ public class DefaultPluginManager extends AbstractPluginManager {
super();
}
/**
* Use {@link DefaultPluginManager#DefaultPluginManager(Path)}.
*
* @param pluginsDir
*/
@Deprecated
public DefaultPluginManager(File pluginsDir) {
this(pluginsDir.toPath());
@ -46,14 +51,11 @@ public class DefaultPluginManager extends AbstractPluginManager {
super(pluginsRoot);
}
/**
* By default if {@link DefaultPluginManager#isDevelopment()} returns {@code true}
* than a {@link PropertiesPluginDescriptorFinder} is returned
* else this method returns {@link DefaultPluginDescriptorFinder}.
*/
@Override
protected PluginDescriptorFinder createPluginDescriptorFinder() {
return isDevelopment() ? new PropertiesPluginDescriptorFinder() : new DefaultPluginDescriptorFinder(pluginClasspath);
protected CompoundPluginDescriptorFinder createPluginDescriptorFinder() {
return new CompoundPluginDescriptorFinder()
.add(new PropertiesPluginDescriptorFinder())
.add(new ManifestPluginDescriptorFinder());
}
@Override

23
pf4j/src/main/java/org/pf4j/JarPluginManager.java

@ -19,15 +19,12 @@ import org.pf4j.util.AndFileFilter;
import org.pf4j.util.DirectoryFileFilter;
import org.pf4j.util.HiddenFilter;
import org.pf4j.util.JarFileFilter;
import org.pf4j.util.NameFileFilter;
import org.pf4j.util.NotFileFilter;
import org.pf4j.util.OrFileFilter;
import org.pf4j.util.NameFileFilter;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.file.Path;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
* It's a {@link PluginManager} that loads plugin from a jar file.
@ -43,11 +40,6 @@ public class JarPluginManager extends DefaultPluginManager {
return new JarPluginRepository(getPluginsRoot(), isDevelopment());
}
@Override
protected PluginDescriptorFinder createPluginDescriptorFinder() {
return isDevelopment() ? new PropertiesPluginDescriptorFinder() : new JarPluginDescriptorFinder();
}
@Override
protected PluginLoader createPluginLoader() {
return new JarPluginLoader(this, pluginClasspath);
@ -79,19 +71,6 @@ public class JarPluginManager extends DefaultPluginManager {
}
class JarPluginDescriptorFinder extends ManifestPluginDescriptorFinder {
@Override
public Manifest readManifest(Path pluginPath) throws PluginException {
try {
return new JarFile(pluginPath.toFile()).getManifest();
} catch (IOException e) {
throw new PluginException(e);
}
}
}
class JarPluginLoader extends DefaultPluginLoader {
public JarPluginLoader(PluginManager pluginManager, PluginClasspath pluginClasspath) {

54
pf4j/src/main/java/org/pf4j/ManifestPluginDescriptorFinder.java

@ -15,10 +15,17 @@
*/
package org.pf4j;
import org.pf4j.util.FileUtils;
import org.pf4j.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
@ -26,7 +33,14 @@ import java.util.jar.Manifest;
*
* @author Decebal Suiu
*/
public abstract class ManifestPluginDescriptorFinder implements PluginDescriptorFinder {
public class ManifestPluginDescriptorFinder implements PluginDescriptorFinder {
private static final Logger log = LoggerFactory.getLogger(ManifestPluginDescriptorFinder.class);
@Override
public boolean isApplicable(Path pluginPath) {
return Files.exists(pluginPath) && (Files.isDirectory(pluginPath) || FileUtils.isJarFile(pluginPath));
}
@Override
public PluginDescriptor find(Path pluginPath) throws PluginException {
@ -35,7 +49,43 @@ public abstract class ManifestPluginDescriptorFinder implements PluginDescriptor
return createPluginDescriptor(manifest);
}
public abstract Manifest readManifest(Path pluginPath) throws PluginException;
protected Manifest readManifest(Path pluginPath) throws PluginException {
if (FileUtils.isJarFile(pluginPath)) {
try {
Manifest manifest = new JarFile(pluginPath.toFile()).getManifest();
if (manifest != null) {
return manifest;
}
} catch (IOException e) {
throw new PluginException(e);
}
}
Path manifestPath = getManifestPath(pluginPath);
if (manifestPath == null) {
throw new PluginException("Cannot find the manifest path");
}
log.debug("Lookup plugin descriptor in '{}'", manifestPath);
if (Files.notExists(manifestPath)) {
throw new PluginException("Cannot find '{}' path", manifestPath);
}
try (InputStream input = Files.newInputStream(manifestPath)) {
return new Manifest(input);
} catch (IOException e) {
throw new PluginException(e);
}
}
protected Path getManifestPath(Path pluginPath) throws PluginException {
if (Files.isDirectory(pluginPath)) {
// legacy (the path is something like "classes/META-INF/MANIFEST.MF")
return FileUtils.findFile(pluginPath,"MANIFEST.MF");
}
return null;
}
protected PluginDescriptor createPluginDescriptor(Manifest manifest) {
PluginDescriptor pluginDescriptor = createPluginDescriptorInstance();

13
pf4j/src/main/java/org/pf4j/PluginDescriptorFinder.java

@ -19,13 +19,22 @@ import java.nio.file.Path;
/**
* Find a plugin descriptor for a plugin path.
* You can find in manifest file {@link DefaultPluginDescriptorFinder},
* xml file, properties file, java services (with {@link java.util.ServiceLoader}), etc.
* You can find the plugin descriptor in manifest file {@link ManifestPluginDescriptorFinder},
* properties file {@link PropertiesPluginDescriptorFinder}, xml file,
* java services (with {@link java.util.ServiceLoader}), etc.
*
* @author Decebal Suiu
*/
public interface PluginDescriptorFinder {
/**
* Returns true if this finder is applicable to the given {@link Path}.
*
* @param pluginPath
* @return
*/
boolean isApplicable(Path pluginPath);
PluginDescriptor find(Path pluginPath) throws PluginException;
}

27
pf4j/src/main/java/org/pf4j/PropertiesPluginDescriptorFinder.java

@ -15,9 +15,10 @@
*/
package org.pf4j;
import org.pf4j.util.FileUtils;
import org.pf4j.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.pf4j.util.StringUtils;
import java.io.IOException;
import java.io.InputStream;
@ -47,7 +48,12 @@ public class PropertiesPluginDescriptorFinder implements PluginDescriptorFinder
this.propertiesFileName = propertiesFileName;
}
@Override
@Override
public boolean isApplicable(Path pluginPath) {
return Files.exists(pluginPath) && (Files.isDirectory(pluginPath) || FileUtils.isJarFile(pluginPath));
}
@Override
public PluginDescriptor find(Path pluginPath) throws PluginException {
Properties properties = readProperties(pluginPath);
@ -56,6 +62,10 @@ public class PropertiesPluginDescriptorFinder implements PluginDescriptorFinder
protected Properties readProperties(Path pluginPath) throws PluginException {
Path propertiesPath = getPropertiesPath(pluginPath, propertiesFileName);
if (propertiesPath == null) {
throw new PluginException("Cannot find the properties path");
}
log.debug("Lookup plugin descriptor in '{}'", propertiesPath);
if (Files.notExists(propertiesPath)) {
throw new PluginException("Cannot find '{}' path", propertiesPath);
@ -65,14 +75,23 @@ public class PropertiesPluginDescriptorFinder implements PluginDescriptorFinder
try (InputStream input = Files.newInputStream(propertiesPath)) {
properties.load(input);
} catch (IOException e) {
throw new PluginException(e.getMessage(), e);
throw new PluginException(e);
}
return properties;
}
protected Path getPropertiesPath(Path pluginPath, String propertiesFileName) throws PluginException {
return pluginPath.resolve(Paths.get(propertiesFileName));
if (Files.isDirectory(pluginPath)) {
return pluginPath.resolve(Paths.get(propertiesFileName));
} else {
// it's a jar file
try {
return FileUtils.getPath(pluginPath, propertiesFileName);
} catch (IOException e) {
throw new PluginException(e);
}
}
}
protected PluginDescriptor createPluginDescriptor(Properties properties) {

9
pf4j/src/main/java/org/pf4j/ServiceProviderExtensionFinder.java

@ -16,6 +16,7 @@
package org.pf4j;
import org.pf4j.processor.ServiceProviderExtensionStorage;
import org.pf4j.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -24,8 +25,6 @@ import java.io.Reader;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
@ -65,8 +64,7 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder {
if (url != null) {
Path extensionPath;
if (url.toURI().getScheme().equals("jar")) {
FileSystem fileSystem = FileSystems.newFileSystem(url.toURI(), Collections.<String, Object>emptyMap());
extensionPath = fileSystem.getPath(getExtensionsResource());
extensionPath = FileUtils.getPath(url.toURI(), getExtensionsResource());
} else {
extensionPath = Paths.get(url.toURI());
}
@ -100,8 +98,7 @@ public class ServiceProviderExtensionFinder extends AbstractExtensionFinder {
if (url != null) {
Path extensionPath;
if (url.toURI().getScheme().equals("jar")) {
FileSystem fileSystem = FileSystems.newFileSystem(url.toURI(), Collections.<String, Object>emptyMap());
extensionPath = fileSystem.getPath(getExtensionsResource());
extensionPath = FileUtils.getPath(url.toURI(), getExtensionsResource());
} else {
extensionPath = Paths.get(url.toURI());
}

49
pf4j/src/main/java/org/pf4j/util/FileUtils.java

@ -23,7 +23,10 @@ import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
@ -32,6 +35,7 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
@ -199,4 +203,49 @@ public class FileUtils {
return Files.isRegularFile(path) && path.toString().toLowerCase().endsWith(".zip");
}
/**
* Return true only if path is a jar file.
*
* @param path to a file/dir
* @return true if file with {@code .jar} ending
*/
public static boolean isJarFile(Path path) {
return Files.isRegularFile(path) && path.toString().toLowerCase().endsWith(".jar");
}
public static Path getPath(Path path, String first, String... more) throws IOException {
URI uri = path.toUri();
if (isJarFile(path)) {
uri = URI.create("jar:file:" + path.toString());
}
return getPath(uri, first, more);
}
public static Path getPath(URI uri, String first, String... more) throws IOException {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, String>emptyMap());
return fileSystem.getPath(first, more);
}
public static Path findFile(Path directoryPath, String fileName) {
File[] files = directoryPath.toFile().listFiles();
if (files != null) {
for (File file : files) {
if (file.isFile()) {
if (file.getName().equals(fileName)) {
return file.toPath();
}
} else if (file.isDirectory()) {
Path foundFile = findFile(file.toPath(), fileName);
if (foundFile != null) {
return foundFile;
}
}
}
}
return null;
}
}

104
pf4j/src/test/java/org/pf4j/CompoundPluginDescriptorFinderTest.java

@ -0,0 +1,104 @@
/*
* Copyright 2017 Decebal Suiu
*
* 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.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.pf4j.plugin.PluginZip;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.*;
/**
* @author Decebal Suiu
*/
public class CompoundPluginDescriptorFinderTest {
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
@Test
public void add() {
CompoundPluginDescriptorFinder instance = new CompoundPluginDescriptorFinder();
assertEquals(0, instance.size());
instance.add(new PropertiesPluginDescriptorFinder());
assertEquals(1, instance.size());
}
@Test
public void find() throws Exception {
Path pluginPath = testFolder.newFolder("test-plugin-1").toPath();
Files.write(pluginPath.resolve("plugin.properties"), getPlugin1Properties(), StandardCharsets.UTF_8);
PluginDescriptorFinder instance = new CompoundPluginDescriptorFinder()
.add(new PropertiesPluginDescriptorFinder());
PluginDescriptor pluginDescriptor = instance.find(pluginPath);
assertNotNull(pluginDescriptor);
assertEquals("test-plugin-1", pluginDescriptor.getPluginId());
assertEquals("0.0.1", pluginDescriptor.getVersion());
}
@Test
public void findInJar() throws Exception {
PluginDescriptorFinder instance = new CompoundPluginDescriptorFinder()
.add(new PropertiesPluginDescriptorFinder());
PluginZip pluginJar = new PluginZip.Builder(testFolder.newFile("my-plugin-1.2.3.jar"), "myPlugin")
.pluginVersion("1.2.3")
.build();
PluginDescriptor pluginDescriptor = instance.find(pluginJar.path());
assertNotNull(pluginDescriptor);
assertEquals("myPlugin", pluginJar.pluginId());
assertEquals("1.2.3", pluginJar.pluginVersion());
}
@Test(expected = PluginException.class)
public void testNotFound() throws Exception {
PluginDescriptorFinder instance = new CompoundPluginDescriptorFinder();
instance.find(getPluginsRoot().resolve("test-plugin-3"));
}
private List<String> getPlugin1Properties() {
String[] lines = new String[] {
"plugin.id=test-plugin-1\n"
+ "plugin.version=0.0.1\n"
+ "plugin.description=Test Plugin 1\n"
+ "plugin.provider=Decebal Suiu\n"
+ "plugin.class=org.pf4j.plugin.TestPlugin\n"
+ "plugin.dependencies=test-plugin-2,test-plugin-3@~1.0\n"
+ "plugin.requires=>=1\n"
+ "plugin.license=Apache-2.0\n"
+ "\n"
+ ""
};
return Arrays.asList(lines);
}
private Path getPluginsRoot() {
return testFolder.getRoot().toPath();
}
}

153
pf4j/src/test/java/org/pf4j/LoadPluginsTest.java

@ -16,49 +16,42 @@
package org.pf4j;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.pf4j.plugin.MockPluginManager;
import org.junit.rules.TemporaryFolder;
import org.pf4j.plugin.PluginZip;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.nio.file.*;
import java.util.Collections;
import java.nio.file.Files;
import java.nio.file.Paths;
import static junit.framework.TestCase.assertNull;
import static org.junit.Assert.*;
public class LoadPluginsTest {
private Path tmpDir;
private MockPluginManager pluginManager;
private MockZipPlugin p1;
private MockZipPlugin p2;
private MockZipPlugin p3;
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
private DefaultPluginManager pluginManager;
@Before
public void setup() throws IOException {
tmpDir = Files.createTempDirectory("pf4j-test");
tmpDir.toFile().deleteOnExit();
p1 = new MockZipPlugin("myPlugin", "1.2.3", "my-plugin-1.2.3", "my-plugin-1.2.3.zip");
p2 = new MockZipPlugin("myPlugin", "2.0.0", "my-plugin-2.0.0", "my-plugin-2.0.0.ZIP");
p3 = new MockZipPlugin("other", "3.0.0", "other-3.0.0", "other-3.0.0.Zip");
pluginManager = new MockPluginManager(
tmpDir,
new PropertiesPluginDescriptorFinder("my.properties"));
pluginManager = new DefaultPluginManager(testFolder.getRoot().toPath());
}
@Test
public void load() throws Exception {
p1.create();
assertTrue(Files.exists(p1.zipFile));
PluginZip pluginZip = new PluginZip.Builder(testFolder.newFile("my-plugin-1.2.3.zip"), "myPlugin")
.pluginVersion("1.2.3")
.build();
assertTrue(Files.exists(pluginZip.path()));
assertEquals(0, pluginManager.getPlugins().size());
pluginManager.loadPlugins();
assertTrue(Files.exists(p1.zipFile));
assertTrue(Files.exists(p1.unzipped));
assertTrue(Files.exists(pluginZip.path()));
assertTrue(Files.exists(pluginZip.unzippedPath()));
assertEquals(1, pluginManager.getPlugins().size());
assertEquals(p1.id, pluginManager.idForPath(p1.unzipped));
assertEquals(pluginZip.pluginId(), pluginManager.idForPath(pluginZip.unzippedPath()));
}
@Test(expected = IllegalArgumentException.class)
@ -68,105 +61,93 @@ public class LoadPluginsTest {
@Test
public void loadTwiceFails() throws Exception {
p1.create();
assertNotNull(pluginManager.loadPluginFromPath(p1.zipFile));
assertNull(pluginManager.loadPluginFromPath(p1.zipFile));
PluginZip pluginZip = new PluginZip.Builder(testFolder.newFile("my-plugin-1.2.3.zip"), "myPlugin")
.pluginVersion("1.2.3")
.build();
assertNotNull(pluginManager.loadPluginFromPath(pluginZip.path()));
assertNull(pluginManager.loadPluginFromPath(pluginZip.path()));
}
@Test
public void loadUnloadLoad() throws Exception {
p1.create();
PluginZip pluginZip = new PluginZip.Builder(testFolder.newFile("my-plugin-1.2.3.zip"), "myPlugin")
.pluginVersion("1.2.3")
.build();
pluginManager.loadPlugins();
assertEquals(1, pluginManager.getPlugins().size());
assertTrue(pluginManager.unloadPlugin(pluginManager.idForPath(p1.unzipped)));
assertTrue(pluginManager.unloadPlugin(pluginManager.idForPath(pluginZip.unzippedPath())));
// duplicate check
assertNull(pluginManager.idForPath(p1.unzipped));
assertNull(pluginManager.idForPath(pluginZip.unzippedPath()));
// Double unload ok
assertFalse(pluginManager.unloadPlugin(pluginManager.idForPath(p1.unzipped)));
assertNotNull(pluginManager.loadPlugin(p1.unzipped));
assertFalse(pluginManager.unloadPlugin(pluginManager.idForPath(pluginZip.unzippedPath())));
assertNotNull(pluginManager.loadPlugin(pluginZip.unzippedPath()));
}
@Test
public void upgrade() throws Exception {
p1.create();
new PluginZip.Builder(testFolder.newFile("my-plugin-1.2.3.zip"), "myPlugin")
.pluginVersion("1.2.3")
.build();
pluginManager.loadPlugins();
pluginManager.startPlugins();
assertEquals(1, pluginManager.getPlugins().size());
assertEquals("1.2.3", pluginManager.getPlugin(p2.id).getDescriptor().getVersion());
assertEquals(1, pluginManager.getStartedPlugins().size());
p2.create();
PluginZip pluginZip2 = new PluginZip.Builder(testFolder.newFile("my-plugin-2.0.0.ZIP"), "myPlugin")
.pluginVersion("2.0.0")
.build();
assertEquals("1.2.3", pluginManager.getPlugin(pluginZip2.pluginId()).getDescriptor().getVersion());
pluginManager.loadPlugins();
pluginManager.startPlugin(p2.id);
pluginManager.startPlugin(pluginZip2.pluginId());
assertEquals(1, pluginManager.getPlugins().size());
assertEquals("2.0.0", pluginManager.getPlugin(p2.id).getDescriptor().getVersion());
assertEquals("2.0.0", pluginManager.getPlugin(pluginZip2.pluginId()).getDescriptor().getVersion());
assertEquals("2.0.0", pluginManager.getStartedPlugins().get(1).getDescriptor().getVersion());
}
@Test
public void getRoot() throws Exception {
assertEquals(tmpDir, pluginManager.getPluginsRoot());
assertEquals(testFolder.getRoot().toPath(), pluginManager.getPluginsRoot());
}
@Test
public void notAPlugin() throws Exception {
Path notAPlugin = tmpDir.resolve("not-a-zip");
Files.createFile(notAPlugin);
testFolder.newFile("not-a-zip");
pluginManager.loadPlugins();
assertEquals(0, pluginManager.getPlugins().size());
}
@Test
public void deletePlugin() throws Exception {
p1.create();
p3.create();
PluginZip pluginZip1 = new PluginZip.Builder(testFolder.newFile("my-plugin-1.2.3.zip"), "myPlugin")
.pluginVersion("1.2.3")
.build();
PluginZip pluginZip3 = new PluginZip.Builder(testFolder.newFile("other-3.0.0.Zip"), "other")
.pluginVersion("3.0.0")
.build();
pluginManager.loadPlugins();
pluginManager.startPlugins();
assertEquals(2, pluginManager.getPlugins().size());
pluginManager.deletePlugin(p1.id);
assertEquals(1, pluginManager.getPlugins().size());
assertFalse(Files.exists(p1.zipFile));
assertFalse(Files.exists(p1.unzipped));
assertTrue(Files.exists(p3.zipFile));
assertTrue(Files.exists(p3.unzipped));
}
private class MockZipPlugin {
public final String id;
public final String version;
public final String filename;
public final Path zipFile;
public final Path unzipped;
public final Path propsFile;
public final URI fileURI;
public String zipname;
public MockZipPlugin(String id, String version, String filename, String zipname) throws IOException {
this.id = id;
this.version = version;
this.filename = filename;
this.zipname = zipname;
zipFile = tmpDir.resolve(zipname).toAbsolutePath();
unzipped = tmpDir.resolve(filename);
propsFile = tmpDir.resolve("my.properties");
fileURI = URI.create("jar:file:"+zipFile.toString());
}
public void create() throws IOException {
try (FileSystem zipfs = FileSystems.newFileSystem(fileURI, Collections.singletonMap("create", "true"))) {
Path propsInZip = zipfs.getPath("/" + propsFile.getFileName().toString());
BufferedWriter br = new BufferedWriter(new FileWriter(propsFile.toString()));
br.write("plugin.id=" + id);
br.newLine();
br.write("plugin.version=" + version);
br.newLine();
br.write("plugin.class=org.pf4j.plugin.TestPlugin");
br.close();
Files.move(propsFile, propsInZip);
}
}
pluginManager.deletePlugin(pluginZip1.pluginId());
assertEquals(1, pluginManager.getPlugins().size());
assertFalse(Files.exists(pluginZip1.path()));
assertFalse(Files.exists(pluginZip1.unzippedPath()));
assertTrue(Files.exists(pluginZip3.path()));
assertTrue(Files.exists(pluginZip3.unzippedPath()));
}
}

8
pf4j/src/test/java/org/pf4j/ManifestPluginDescriptorFinderTest.java

@ -74,11 +74,11 @@ public class ManifestPluginDescriptorFinderTest {
}
/**
* Test of {@link DefaultPluginDescriptorFinder#find(Path)} method.
* Test of {@link ManifestPluginDescriptorFinder#find(Path)} method.
*/
@Test
public void testFind() throws Exception {
PluginDescriptorFinder instance = new DefaultPluginDescriptorFinder(new DefaultPluginClasspath());
PluginDescriptorFinder instance = new ManifestPluginDescriptorFinder();
PluginDescriptor plugin1 = instance.find(getPluginsRoot().resolve("test-plugin-1"));
PluginDescriptor plugin2 = instance.find(getPluginsRoot().resolve("test-plugin-2"));
@ -105,11 +105,11 @@ public class ManifestPluginDescriptorFinderTest {
}
/**
* Test of {@link DefaultPluginDescriptorFinder#find(Path)} method.
* Test of {@link ManifestPluginDescriptorFinder#find(Path)} method.
*/
@Test(expected = PluginException.class)
public void testFindNotFound() throws Exception {
PluginDescriptorFinder instance = new DefaultPluginDescriptorFinder(new DefaultPluginClasspath());
PluginDescriptorFinder instance = new ManifestPluginDescriptorFinder();
instance.find(getPluginsRoot().resolve("test-plugin-3"));
}

18
pf4j/src/test/java/org/pf4j/PropertiesPluginDescriptorFinderTest.java

@ -19,6 +19,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.pf4j.plugin.PluginZip;
import java.io.IOException;
import java.nio.charset.Charset;
@ -96,11 +97,26 @@ public class PropertiesPluginDescriptorFinderTest {
}
@Test(expected = PluginException.class)
public void testFindNotFound() throws Exception {
public void testNotFound() throws Exception {
PluginDescriptorFinder instance = new PropertiesPluginDescriptorFinder();
instance.find(getPluginsRoot().resolve("test-plugin-3"));
}
@Test
public void findInJar() throws Exception {
PluginZip pluginJar = new PluginZip.Builder(testFolder.newFile("my-plugin-1.2.3.jar"), "myPlugin")
.pluginVersion("1.2.3")
.build();
assertTrue(Files.exists(pluginJar.path()));
PluginDescriptorFinder instance = new PropertiesPluginDescriptorFinder();
PluginDescriptor pluginDescriptor = instance.find(pluginJar.path());
assertNotNull(pluginDescriptor);
assertEquals("myPlugin", pluginJar.pluginId());
assertEquals("1.2.3", pluginJar.pluginVersion());
}
private List<String> getPlugin1Properties() {
String[] lines = new String[] {
"plugin.id=test-plugin-1\n"

1
pf4j/src/test/java/org/pf4j/plugin/AnotherFailTestPlugin.java

@ -18,7 +18,6 @@ package org.pf4j.plugin;
import org.pf4j.Plugin;
/**
*
* @author Mario Franco
*/
public class AnotherFailTestPlugin extends Plugin {

1
pf4j/src/test/java/org/pf4j/plugin/FailTestPlugin.java

@ -16,7 +16,6 @@
package org.pf4j.plugin;
/**
*
* @author Mario Franco
*/
public class FailTestPlugin {

51
pf4j/src/test/java/org/pf4j/plugin/MockPluginManager.java

@ -1,51 +0,0 @@
/*
* Copyright 2017 Decebal Suiu
*
* 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.plugin;
import org.pf4j.DefaultPluginClasspath;
import org.pf4j.DefaultPluginDescriptorFinder;
import org.pf4j.DefaultPluginManager;
import org.pf4j.PluginDescriptorFinder;
import java.nio.file.Path;
/**
* Manager for testing
*/
public class MockPluginManager extends DefaultPluginManager {
private PluginDescriptorFinder finder = new DefaultPluginDescriptorFinder(new DefaultPluginClasspath());
public MockPluginManager() {
super();
}
public MockPluginManager(Path root, PluginDescriptorFinder finder) {
super(root);
this.finder = finder;
}
@Override
protected PluginDescriptorFinder getPluginDescriptorFinder() {
return finder;
}
@Override
protected PluginDescriptorFinder createPluginDescriptorFinder() {
return finder;
}
}

107
pf4j/src/test/java/org/pf4j/plugin/PluginZip.java

@ -0,0 +1,107 @@
/*
* Copyright 2015 Decebal Suiu
*
* 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.plugin;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* Represents a plugin zip/jar file.
* The "plugin.properties" file is created on the fly from the information supplied in Builder.
*
* @author Decebal Suiu
*/
public class PluginZip {
private final File file;
private final String pluginId;
private final String pluginVersion;
protected PluginZip(Builder builder) {
this.file = builder.file;
this.pluginId = builder.pluginId;
this.pluginVersion = builder.pluginVersion;
}
public File file() {
return file;
}
public Path path() {
return file.toPath();
}
public String pluginId() {
return pluginId;
}
public String pluginVersion() {
return pluginVersion;
}
public Path unzippedPath() {
Path path = path();
String fileName = path.getFileName().toString();
return path.getParent().resolve(fileName.substring(0, fileName.length() - 4)); // without ".zip" suffix
}
public static class Builder {
private final File file;
private final String pluginId;
private String pluginVersion;
public Builder(File file, String pluginId) {
this.file = file;
this.pluginId = pluginId;
}
public Builder pluginVersion(String pluginVersion) {
this.pluginVersion = pluginVersion;
return this;
}
public PluginZip build() throws IOException {
createPropertiesFile();
return new PluginZip(this);
}
protected void createPropertiesFile() throws IOException {
Properties properties = new Properties();
properties.setProperty("plugin.id", pluginId);
properties.setProperty("plugin.version", pluginVersion);
properties.setProperty("plugin.class", "org.pf4j.plugin.TestPlugin");
ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(file));
ZipEntry propertiesFile = new ZipEntry("plugin.properties");
outputStream.putNextEntry(propertiesFile);
properties.store(outputStream, "");
outputStream.closeEntry();
outputStream.close();
}
}
}

1
pf4j/src/test/java/org/pf4j/plugin/TestPlugin.java

@ -19,7 +19,6 @@ import org.pf4j.Plugin;
import org.pf4j.PluginWrapper;
/**
*
* @author Mario Franco
*/
public class TestPlugin extends Plugin {

52
pf4j/src/test/java/org/pf4j/util/FileUtilsTest.java

@ -15,60 +15,36 @@
*/
package org.pf4j.util;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.pf4j.plugin.PluginZip;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import static org.junit.Assert.*;
public class FileUtilsTest {
private Path zipFile;
private Path tmpDir;
private Path propsFile;
@Before
public void setup() throws IOException {
tmpDir = Files.createTempDirectory("pf4j-test");
tmpDir.toFile().deleteOnExit();
zipFile = tmpDir.resolve("my.zip").toAbsolutePath();
propsFile = tmpDir.resolve("plugin.properties");
URI file = URI.create("jar:file:"+zipFile.toString());
try (FileSystem zipfs = FileSystems.newFileSystem(file, Collections.singletonMap("create", "true"))) {
Path propsInZip = zipfs.getPath("/plugin.properties");
BufferedWriter br = new BufferedWriter(new FileWriter(propsFile.toString()));
br.write("plugin.id=test");
br.newLine();
br.write("plugin.version=1.2.3");
br.newLine();
br.write("plugin.class=foo.bar");
br.close();
Files.move(propsFile, propsInZip);
}
}
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
@Test
public void expandIfZip() throws Exception {
Path unzipped = FileUtils.expandIfZip(zipFile);
assertEquals(tmpDir.resolve("my"), unzipped);
assertTrue(Files.exists(tmpDir.resolve("my/plugin.properties")));
PluginZip pluginZip = new PluginZip.Builder(testFolder.newFile("my-plugin-1.2.3.zip"), "myPlugin")
.pluginVersion("1.2.3")
.build();
Path unzipped = FileUtils.expandIfZip(pluginZip.path());
assertEquals(pluginZip.unzippedPath(), unzipped);
assertTrue(Files.exists(unzipped.resolve("plugin.properties")));
// Non-zip file remains unchanged
assertEquals(propsFile, FileUtils.expandIfZip(propsFile));
// File without .suffix
Path extra = Files.createFile(tmpDir.resolve("extra"));
Path extra = testFolder.newFile("extra").toPath();
assertEquals(extra, FileUtils.expandIfZip(extra));
// Folder
Path folder = Files.createFile(tmpDir.resolve("folder"));
Path folder = testFolder.newFile("folder").toPath();
assertEquals(folder, FileUtils.expandIfZip(folder));
}

Loading…
Cancel
Save