Browse Source

Add CompoundPluginDescriptorFinder (#172)

tags/release-2.0.0
Decebal Suiu 6 years ago
parent
commit
1822cdede3

+ 3
- 1
pf4j/src/main/java/org/pf4j/AbstractPluginManager.java View File

@@ -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
- 0
pf4j/src/main/java/org/pf4j/CompoundPluginDescriptorFinder.java View File

@@ -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);
}

}

+ 4
- 7
pf4j/src/main/java/org/pf4j/DefaultExtensionFinder.java View File

@@ -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;

+ 0
- 64
pf4j/src/main/java/org/pf4j/DefaultPluginDescriptorFinder.java View File

@@ -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);
}
}

}

+ 9
- 7
pf4j/src/main/java/org/pf4j/DefaultPluginManager.java View File

@@ -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

+ 1
- 22
pf4j/src/main/java/org/pf4j/JarPluginManager.java View File

@@ -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) {

+ 52
- 2
pf4j/src/main/java/org/pf4j/ManifestPluginDescriptorFinder.java View File

@@ -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();

+ 11
- 2
pf4j/src/main/java/org/pf4j/PluginDescriptorFinder.java View File

@@ -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;

}

+ 23
- 4
pf4j/src/main/java/org/pf4j/PropertiesPluginDescriptorFinder.java View File

@@ -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) {

+ 3
- 6
pf4j/src/main/java/org/pf4j/ServiceProviderExtensionFinder.java View File

@@ -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
- 0
pf4j/src/main/java/org/pf4j/util/FileUtils.java View File

@@ -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
- 0
pf4j/src/test/java/org/pf4j/CompoundPluginDescriptorFinderTest.java View File

@@ -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();
}

}

+ 67
- 86
pf4j/src/test/java/org/pf4j/LoadPluginsTest.java View File

@@ -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()));
}

}

+ 4
- 4
pf4j/src/test/java/org/pf4j/ManifestPluginDescriptorFinderTest.java View File

@@ -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"));
}


+ 17
- 1
pf4j/src/test/java/org/pf4j/PropertiesPluginDescriptorFinderTest.java View File

@@ -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"

+ 0
- 1
pf4j/src/test/java/org/pf4j/plugin/AnotherFailTestPlugin.java View File

@@ -18,7 +18,6 @@ package org.pf4j.plugin;
import org.pf4j.Plugin;

/**
*
* @author Mario Franco
*/
public class AnotherFailTestPlugin extends Plugin {

+ 0
- 1
pf4j/src/test/java/org/pf4j/plugin/FailTestPlugin.java View File

@@ -16,7 +16,6 @@
package org.pf4j.plugin;

/**
*
* @author Mario Franco
*/
public class FailTestPlugin {

+ 0
- 51
pf4j/src/test/java/org/pf4j/plugin/MockPluginManager.java View File

@@ -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
- 0
pf4j/src/test/java/org/pf4j/plugin/PluginZip.java View File

@@ -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();
}

}

}

+ 0
- 1
pf4j/src/test/java/org/pf4j/plugin/TestPlugin.java View File

@@ -19,7 +19,6 @@ import org.pf4j.Plugin;
import org.pf4j.PluginWrapper;

/**
*
* @author Mario Franco
*/
public class TestPlugin extends Plugin {

+ 14
- 38
pf4j/src/test/java/org/pf4j/util/FileUtilsTest.java View File

@@ -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