mirror of https://github.com/pf4j/pf4j.git
Decebal Suiu
7 years ago
committed by
GitHub
21 changed files with 549 additions and 298 deletions
@ -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); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -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(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue