aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDecebal Suiu <decebal.suiu@gmail.com>2019-05-31 20:02:09 +0300
committerDecebal Suiu <decebal.suiu@gmail.com>2019-05-31 20:02:09 +0300
commit6fd8ae23848fafaadb37d0e9e9169e0c1dc4ccb2 (patch)
tree7a6757d1e884c9846d5003be99123dca798e7fe3
parent733fb970b4523f61832f0f92f8b4c90daf949487 (diff)
downloadpf4j-6fd8ae23848fafaadb37d0e9e9169e0c1dc4ccb2.tar.gz
pf4j-6fd8ae23848fafaadb37d0e9e9169e0c1dc4ccb2.zip
Improve PluginJar, add ClassDataProvider concept
-rw-r--r--pf4j/src/test/java/org/pf4j/JarPluginManagerTest.java16
-rw-r--r--pf4j/src/test/java/org/pf4j/plugin/ClassDataProvider.java33
-rw-r--r--pf4j/src/test/java/org/pf4j/plugin/DefaultClassDataProvider.java55
-rw-r--r--pf4j/src/test/java/org/pf4j/plugin/FailTestExtension.java5
-rw-r--r--pf4j/src/test/java/org/pf4j/plugin/PluginJar.java60
-rw-r--r--pf4j/src/test/java/org/pf4j/plugin/TestExtension.java5
-rw-r--r--pf4j/src/test/java/org/pf4j/plugin/TestExtensionPoint.java2
7 files changed, 170 insertions, 6 deletions
diff --git a/pf4j/src/test/java/org/pf4j/JarPluginManagerTest.java b/pf4j/src/test/java/org/pf4j/JarPluginManagerTest.java
index 45c3999..d9ca90a 100644
--- a/pf4j/src/test/java/org/pf4j/JarPluginManagerTest.java
+++ b/pf4j/src/test/java/org/pf4j/JarPluginManagerTest.java
@@ -20,10 +20,13 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.pf4j.plugin.PluginJar;
+import org.pf4j.plugin.TestExtension;
+import org.pf4j.plugin.TestExtensionPoint;
import org.pf4j.plugin.TestPlugin;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -42,6 +45,7 @@ public class JarPluginManagerTest {
pluginJar = new PluginJar.Builder(pluginsPath.resolve("test-plugin.jar"), "test-plugin")
.pluginClass(TestPlugin.class.getName())
.pluginVersion("1.2.3")
+ .extension(TestExtension.class.getName())
.build();
pluginManager = new JarPluginManager(pluginsPath);
@@ -54,6 +58,18 @@ public class JarPluginManagerTest {
}
@Test
+ public void getExtensions() {
+ pluginManager.loadPlugins();
+ pluginManager.startPlugins();
+
+ List<TestExtensionPoint> extensions = pluginManager.getExtensions(TestExtensionPoint.class);
+ assertEquals(1, extensions.size());
+
+ String something = extensions.get(0).saySomething();
+ assertEquals(new TestExtension().saySomething(), something);
+ }
+
+ @Test
public void unloadPlugin() throws Exception {
pluginManager.loadPlugins();
diff --git a/pf4j/src/test/java/org/pf4j/plugin/ClassDataProvider.java b/pf4j/src/test/java/org/pf4j/plugin/ClassDataProvider.java
new file mode 100644
index 0000000..ff55967
--- /dev/null
+++ b/pf4j/src/test/java/org/pf4j/plugin/ClassDataProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pf4j.plugin;
+
+/**
+ * Defines the interface for classes that know to supply class data for a class name.
+ * The idea is to have the possibility to retrieve the data for a class from different sources:
+ * <ul>
+ * <li>Class path - the class is already loaded by the class loader</li>
+ * <li>String - the string (the source code) is compiled dynamically via {@link javax.tools.JavaCompiler}</>
+ * <li>Generate the source code programmatically using something like {@code https://github.com/square/javapoet}</li>
+ * </ul>
+ *
+ * @author Decebal Suiu
+ */
+public interface ClassDataProvider {
+
+ byte[] getClassData(String className);
+
+}
diff --git a/pf4j/src/test/java/org/pf4j/plugin/DefaultClassDataProvider.java b/pf4j/src/test/java/org/pf4j/plugin/DefaultClassDataProvider.java
new file mode 100644
index 0000000..ef0eaf9
--- /dev/null
+++ b/pf4j/src/test/java/org/pf4j/plugin/DefaultClassDataProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pf4j.plugin;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Get class data from the class path.
+ *
+ * @author Decebal Suiu
+ */
+public class DefaultClassDataProvider implements ClassDataProvider {
+
+ @Override
+ public byte[] getClassData(String className) {
+ String path = className.replace('.', '/') + ".class";
+ InputStream classDataStream = getClass().getClassLoader().getResourceAsStream(path);
+ if (classDataStream == null) {
+ throw new RuntimeException("Cannot find class data");
+ }
+
+ try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+ copyStream(classDataStream, outputStream);
+ return outputStream.toByteArray();
+ } catch (IOException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ private void copyStream(InputStream in, OutputStream out) throws IOException {
+ byte[] buffer = new byte[1024];
+
+ int bytesRead;
+ while ((bytesRead = in.read(buffer)) != -1) {
+ out.write(buffer, 0, bytesRead);
+ }
+ }
+
+}
diff --git a/pf4j/src/test/java/org/pf4j/plugin/FailTestExtension.java b/pf4j/src/test/java/org/pf4j/plugin/FailTestExtension.java
index 9cc37e0..13b51ee 100644
--- a/pf4j/src/test/java/org/pf4j/plugin/FailTestExtension.java
+++ b/pf4j/src/test/java/org/pf4j/plugin/FailTestExtension.java
@@ -26,4 +26,9 @@ public class FailTestExtension implements TestExtensionPoint {
public FailTestExtension(String name) {
}
+ @Override
+ public String saySomething() {
+ return "I am a fail test extension";
+ }
+
}
diff --git a/pf4j/src/test/java/org/pf4j/plugin/PluginJar.java b/pf4j/src/test/java/org/pf4j/plugin/PluginJar.java
index 366c22a..a75b68f 100644
--- a/pf4j/src/test/java/org/pf4j/plugin/PluginJar.java
+++ b/pf4j/src/test/java/org/pf4j/plugin/PluginJar.java
@@ -17,18 +17,23 @@ package org.pf4j.plugin;
import org.pf4j.ManifestPluginDescriptorFinder;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
import java.nio.file.Path;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.Map;
+import java.util.Set;
import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
/**
- /**
* Represents a plugin {@code jar} file.
* The {@code MANIFEST.MF} file is created on the fly from the information supplied in {@link Builder}.
*
@@ -87,6 +92,8 @@ public class PluginJar {
private String pluginClass;
private String pluginVersion;
private Map<String, String> manifestAttributes = new LinkedHashMap<>();
+ private Set<String> extensions = new LinkedHashSet<>();
+ private ClassDataProvider classDataProvider = new DefaultClassDataProvider();
public Builder(Path path, String pluginId) {
this.path = path;
@@ -125,13 +132,44 @@ public class PluginJar {
return this;
}
+ public Builder extension(String extensionClassName) {
+ extensions.add(extensionClassName);
+
+ return this;
+ }
+
+ public Builder classDataProvider(ClassDataProvider classDataProvider) {
+ this.classDataProvider = classDataProvider;
+
+ return this;
+ }
+
public PluginJar build() throws IOException {
- createManifestFile();
+ Manifest manifest = createManifest();
+ try (OutputStream outputStream = new FileOutputStream(path.toFile())) {
+ JarOutputStream jarOutputStream = new JarOutputStream(outputStream, manifest);
+ if (!extensions.isEmpty()) {
+ // add extensions.idx
+ JarEntry jarEntry = new JarEntry("META-INF/extensions.idx");
+ jarOutputStream.putNextEntry(jarEntry);
+ jarOutputStream.write(extensionsAsByteArray());
+ jarOutputStream.closeEntry();
+ // add extensions classes
+ for (String extension : extensions) {
+ String extensionPath = extension.replace('.', '/') + ".class";
+ JarEntry classEntry = new JarEntry(extensionPath);
+ jarOutputStream.putNextEntry(classEntry);
+ jarOutputStream.write(classDataProvider.getClassData(extension));
+ jarOutputStream.closeEntry();
+ }
+ }
+ jarOutputStream.close();
+ }
return new PluginJar(this);
}
- protected void createManifestFile() throws IOException {
+ private Manifest createManifest() {
Map<String, String> map = new LinkedHashMap<>();
map.put(ManifestPluginDescriptorFinder.PLUGIN_ID, pluginId);
map.put(ManifestPluginDescriptorFinder.PLUGIN_VERSION, pluginVersion);
@@ -142,9 +180,19 @@ public class PluginJar {
map.putAll(manifestAttributes);
}
- Manifest manifest = createManifest(map);
- JarOutputStream outputStream = new JarOutputStream(new FileOutputStream(path.toFile()), manifest);
- outputStream.close();
+ return PluginJar.createManifest(map);
+ }
+
+ private byte[] extensionsAsByteArray() throws IOException {
+ try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+ PrintWriter writer = new PrintWriter(outputStream);
+ for (String extension : extensions) {
+ writer.println(extension);
+ }
+ writer.flush();
+
+ return outputStream.toByteArray();
+ }
}
}
diff --git a/pf4j/src/test/java/org/pf4j/plugin/TestExtension.java b/pf4j/src/test/java/org/pf4j/plugin/TestExtension.java
index 5f48c9a..83bc0b5 100644
--- a/pf4j/src/test/java/org/pf4j/plugin/TestExtension.java
+++ b/pf4j/src/test/java/org/pf4j/plugin/TestExtension.java
@@ -23,4 +23,9 @@ import org.pf4j.Extension;
@Extension
public class TestExtension implements TestExtensionPoint {
+ @Override
+ public String saySomething() {
+ return "I am a test extension";
+ }
+
}
diff --git a/pf4j/src/test/java/org/pf4j/plugin/TestExtensionPoint.java b/pf4j/src/test/java/org/pf4j/plugin/TestExtensionPoint.java
index a33ac40..d29a7ab 100644
--- a/pf4j/src/test/java/org/pf4j/plugin/TestExtensionPoint.java
+++ b/pf4j/src/test/java/org/pf4j/plugin/TestExtensionPoint.java
@@ -22,4 +22,6 @@ import org.pf4j.ExtensionPoint;
*/
public interface TestExtensionPoint extends ExtensionPoint {
+ String saySomething();
+
}