}
// 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();
--- /dev/null
+/*
+ * 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);
+ }
+
+}
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
return extensions;
}
-
@Override
public Set<String> findClassNames(String pluginId) {
Set<String> classNames = new HashSet<>();
}
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;
+++ /dev/null
-/*
- * 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);
- }
- }
-
-}
super();
}
+ /**
+ * Use {@link DefaultPluginManager#DefaultPluginManager(Path)}.
+ *
+ * @param pluginsDir
+ */
@Deprecated
public DefaultPluginManager(File pluginsDir) {
this(pluginsDir.toPath());
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
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.
return new JarPluginRepository(getPluginsRoot(), isDevelopment());
}
- @Override
- protected PluginDescriptorFinder createPluginDescriptorFinder() {
- return isDevelopment() ? new PropertiesPluginDescriptorFinder() : new JarPluginDescriptorFinder();
- }
-
@Override
protected PluginLoader createPluginLoader() {
return new JarPluginLoader(this, pluginClasspath);
}
- 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) {
*/
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;
/**
*
* @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 {
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();
/**
* 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;
}
*/
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;
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);
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);
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) {
package org.pf4j;
import org.pf4j.processor.ServiceProviderExtensionStorage;
+import org.pf4j.util.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
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());
}
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());
}
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;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
/**
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;
+ }
+
}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
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)
@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()));
}
}
}
/**
- * 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"));
}
/**
- * 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"));
}
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;
}
@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"
import org.pf4j.Plugin;
/**
- *
* @author Mario Franco
*/
public class AnotherFailTestPlugin extends Plugin {
package org.pf4j.plugin;
/**
- *
* @author Mario Franco
*/
public class FailTestPlugin {
+++ /dev/null
-/*
- * 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;
- }
-
-}
--- /dev/null
+/*
+ * 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();
+ }
+
+ }
+
+}
import org.pf4j.PluginWrapper;
/**
- *
* @author Mario Franco
*/
public class TestPlugin extends Plugin {
*/
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));
}