embulk 0.8.25-java → 0.8.26-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/build.gradle +16 -1
  3. data/embulk-cli/src/main/java/org/embulk/cli/EmbulkMigrate.java +6 -3
  4. data/embulk-core/build.gradle +7 -0
  5. data/embulk-core/src/main/java/org/embulk/EmbulkService.java +2 -0
  6. data/embulk-core/src/main/java/org/embulk/plugin/InjectedPluginSource.java +1 -1
  7. data/embulk-core/src/main/java/org/embulk/plugin/MavenPluginType.java +21 -6
  8. data/embulk-core/src/main/java/org/embulk/plugin/PluginClassLoader.java +42 -2
  9. data/embulk-core/src/main/java/org/embulk/plugin/PluginSourceNotMatchException.java +6 -0
  10. data/embulk-core/src/main/java/org/embulk/plugin/PluginType.java +2 -1
  11. data/embulk-core/src/main/java/org/embulk/plugin/jar/InvalidJarPluginException.java +14 -0
  12. data/embulk-core/src/main/java/org/embulk/plugin/jar/JarPluginLoader.java +205 -0
  13. data/embulk-core/src/main/java/org/embulk/plugin/maven/MavenArtifactFinder.java +134 -0
  14. data/embulk-core/src/main/java/org/embulk/plugin/maven/MavenArtifactNotFoundException.java +20 -0
  15. data/embulk-core/src/main/java/org/embulk/plugin/maven/MavenPluginSource.java +187 -0
  16. data/embulk-core/src/main/java/org/embulk/plugin/maven/MavenPluginSourceModule.java +22 -0
  17. data/embulk-core/src/main/java/org/embulk/plugin/maven/MavenRepositoryNotFoundException.java +31 -0
  18. data/embulk-core/src/main/resources/embulk/parent_first_packages.properties +3 -1
  19. data/embulk-core/src/main/resources/embulk/parent_first_resources.properties +2 -1
  20. data/embulk-core/src/test/java/org/embulk/EmbulkTestRuntime.java +8 -0
  21. data/embulk-core/src/test/java/org/embulk/plugin/TestPluginType.java +24 -0
  22. data/embulk-core/src/test/java/org/embulk/plugin/TestPluginTypeSerDe.java +17 -0
  23. data/embulk-core/src/test/java/org/embulk/plugin/jar/ExampleJarSpiV0.java +9 -0
  24. data/embulk-core/src/test/java/org/embulk/plugin/jar/JarBuilder.java +101 -0
  25. data/embulk-core/src/test/java/org/embulk/plugin/jar/TestJarPluginLoader.java +60 -0
  26. data/embulk-core/src/test/java/org/embulk/plugin/maven/TestMavenArtifactFinder.java +41 -0
  27. data/embulk-core/src/test/resources/m2.test/.gitignore +1 -0
  28. data/embulk-core/src/test/resources/m2.test/org/embulk/example/embulk-example-maven-artifact/0.1.2/embulk-example-maven-artifact-0.1.2.jar +0 -0
  29. data/embulk-core/src/test/resources/m2.test/org/embulk/example/embulk-example-maven-artifact/0.1.2/embulk-example-maven-artifact-0.1.2.jar.sha1 +1 -0
  30. data/embulk-core/src/test/resources/m2.test/org/embulk/example/embulk-example-maven-artifact/0.1.2/embulk-example-maven-artifact-0.1.2.pom +9 -0
  31. data/embulk-core/src/test/resources/m2.test/org/embulk/example/embulk-example-maven-artifact/0.1.2/embulk-example-maven-artifact-0.1.2.pom.sha1 +1 -0
  32. data/embulk-docs/src/built-in.rst +26 -9
  33. data/embulk-docs/src/release.rst +1 -0
  34. data/embulk-docs/src/release/release-0.8.26.rst +16 -0
  35. data/embulk-standards/src/main/java/org/embulk/standards/ConfigInputPlugin.java +170 -0
  36. data/embulk-standards/src/main/java/org/embulk/standards/StandardPluginModule.java +1 -0
  37. data/lib/embulk/version.rb +1 -1
  38. metadata +58 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a2368360f1531d901df3fb7f5d0fe6069ad3362c
4
- data.tar.gz: ef5f5347e9cfabb4ea31d9e29fd69695c9d4ebe4
3
+ metadata.gz: 67e9c5003f422b52f56fd7347f77dda2ea07d86e
4
+ data.tar.gz: ac13f8e09bcc9998ba716fc96e6e98e0546605ef
5
5
  SHA512:
6
- metadata.gz: af58995886e862f1cc30dcbe23813da71f72bd443eb4b9af62584ff5c4aa49ab85a6c53d717e3258f331020e28f4e7b2ff9701c1fde24f1e58d93bff89705387
7
- data.tar.gz: 791c332fcac833460e2a5458d72d8f937ec5881af769fe4100f1b30e225e7b6ed4db0c058f0eec5274f8d3cef56f86a73ff79e95d1987f5f479ad56330f77135
6
+ metadata.gz: 6a275c7189877da26bed04a116dab321b0bf5d9c8f378143aa743c2fa05ae0806fb8d27eabaad76c6bdd7b06971a1b8f5ea2aa8a52152aa7e67a129545e417bc
7
+ data.tar.gz: 6ce56d2cfec57fc2db846f7be7aaf5209e30ac5180b28f0d9930f7cebd333f614e443dcb1e57b49bc58683e4b1a595239809bbe50d4915f9bd21e5d59597abb7
@@ -16,7 +16,7 @@ def release_projects = [project(":embulk-core"), project(":embulk-standards"), p
16
16
 
17
17
  allprojects {
18
18
  group = 'org.embulk'
19
- version = '0.8.25'
19
+ version = '0.8.26'
20
20
 
21
21
  ext {
22
22
  jrubyVersion = '9.1.5.0'
@@ -100,6 +100,9 @@ subprojects {
100
100
  tasks.withType(JavaCompile) {
101
101
  options.compilerArgs << "-Xlint:unchecked" //<< "-Xlint:deprecation"
102
102
  }
103
+ tasks.withType(Test) {
104
+ systemProperties System.properties.findAll { it.key.startsWith("org.embulk") }
105
+ }
103
106
  tasks.withType(FindBugs) {
104
107
  reports {
105
108
  xml.enabled = false
@@ -227,6 +230,18 @@ project(':embulk-cli') {
227
230
  apply plugin: 'com.github.johnrengelman.shadow'
228
231
 
229
232
  shadowJar {
233
+ // 'org.apache.maven' is used in:
234
+ // - embulk-cli: EmbulkMigrate and EmbulkSelfUpdate (from v0.8.17)
235
+ // - embulk-core: MavenPluginSource and the related (from v0.8.26)
236
+ relocate 'org.apache.maven', 'org.embulk.third_party.org.apache.maven'
237
+
238
+ // 'org.codehaus.plexus' is used from 'org.apache.maven'.
239
+ relocate 'org.codehaus.plexus', 'org.embulk.third_party.org.codehaus.plexus'
240
+
241
+ // 'org.eclipse.aether' is used in:
242
+ // - embulk-core: MavenPluginSource and the related (from v0.8.26)
243
+ relocate 'org.eclipse.aether', 'org.embulk.third_party.org.eclipse.aether'
244
+
230
245
  // NOTE: This 'Implementation-Version' in the manifest is referred to provide the Embulk version at runtime.
231
246
  // See also: embulk-core/src/main/java/org/embulk/EmbulkVersion.java
232
247
  manifest {
@@ -10,6 +10,7 @@ import java.nio.file.Path;
10
10
  import java.nio.file.PathMatcher;
11
11
  import java.nio.file.Paths;
12
12
  import java.nio.file.SimpleFileVisitor;
13
+ import java.nio.file.StandardCopyOption;
13
14
  import java.nio.file.StandardOpenOption;
14
15
  import java.nio.file.attribute.BasicFileAttributes;
15
16
  import java.util.ArrayList;
@@ -76,7 +77,7 @@ public class EmbulkMigrate
76
77
  System.out.println("Done. No files are modified.");
77
78
  }
78
79
  else {
79
- System.out.println("Done. Please check modifieid files.");
80
+ System.out.println("Done. Please check modified files.");
80
81
  }
81
82
  }
82
83
 
@@ -236,7 +237,9 @@ public class EmbulkMigrate
236
237
  {
237
238
  Path destinationPath = this.basePath.resolve(destinationFileName);
238
239
  Files.createDirectories(destinationPath.getParent());
239
- Files.copy(EmbulkMigrate.class.getClassLoader().getResourceAsStream(sourceResourcePath), destinationPath);
240
+ Files.copy(EmbulkMigrate.class.getClassLoader().getResourceAsStream(sourceResourcePath), destinationPath,
241
+ StandardCopyOption.REPLACE_EXISTING);
242
+ this.modifiedFiles.add(destinationPath);
240
243
  }
241
244
 
242
245
  public boolean match(String filePath, Pattern pattern)
@@ -424,7 +427,7 @@ public class EmbulkMigrate
424
427
  private static final Pattern OLD_EMBULK_IN_GEMSPEC = Pattern.compile(
425
428
  "embulk-");
426
429
  private static final Pattern GRADLE_VERSION_IN_WRAPPER = Pattern.compile(
427
- "gradle-[23]\\.\\d+(\\.\\d+)?-/");
430
+ "gradle-[23]\\.\\d+(\\.\\d+)?-");
428
431
  private static final Pattern JSON_COLUMN_METHOD_IN_ALL_JAVA = Pattern.compile(
429
432
  "void\\s+jsonColumn");
430
433
  private static final Pattern TIMESTAMP_COLUMN_METHOD_IN_ALL_JAVA = Pattern.compile(
@@ -43,6 +43,13 @@ dependencies {
43
43
  // For embulk/guess/charset.rb. See also embulk.gemspec
44
44
  compile 'com.ibm.icu:icu4j:54.1.1'
45
45
 
46
+ // For MavenPluginSource / MavenArtifactFinder.
47
+ compile 'org.eclipse.aether:aether-api:1.1.0'
48
+ compile 'org.eclipse.aether:aether-spi:1.1.0'
49
+ compile 'org.eclipse.aether:aether-util:1.1.0'
50
+ compile 'org.eclipse.aether:aether-impl:1.1.0'
51
+ compile 'org.apache.maven:maven-aether-provider:3.3.9'
52
+
46
53
  gems 'rubygems:bundler:1.10.6'
47
54
  gems 'rubygems:msgpack:1.1.0'
48
55
  gems 'rubygems:liquid:3.0.6'
@@ -11,6 +11,7 @@ import org.embulk.exec.ExecModule;
11
11
  import org.embulk.exec.ExtensionServiceLoaderModule;
12
12
  import org.embulk.plugin.PluginClassLoaderModule;
13
13
  import org.embulk.plugin.BuiltinPluginSourceModule;
14
+ import org.embulk.plugin.maven.MavenPluginSourceModule;
14
15
  import org.embulk.jruby.JRubyScriptingModule;
15
16
  import static com.google.common.base.Preconditions.checkState;
16
17
 
@@ -45,6 +46,7 @@ public class EmbulkService
45
46
  new ExtensionServiceLoaderModule(systemConfig),
46
47
  new PluginClassLoaderModule(systemConfig),
47
48
  new BuiltinPluginSourceModule(),
49
+ new MavenPluginSourceModule(systemConfig),
48
50
  new JRubyScriptingModule(systemConfig));
49
51
  }
50
52
 
@@ -37,7 +37,7 @@ public class InjectedPluginSource
37
37
  this.injector = injector;
38
38
  }
39
39
 
40
- public static interface PluginFactory <T>
40
+ private static interface PluginFactory <T>
41
41
  {
42
42
  public T newPlugin(Injector injector);
43
43
  }
@@ -10,10 +10,11 @@ import java.util.Objects;
10
10
  public final class MavenPluginType
11
11
  extends PluginType
12
12
  {
13
- private MavenPluginType(final String name, final String group, final String version)
13
+ private MavenPluginType(final String name, final String group, final String classifier, final String version)
14
14
  {
15
15
  super("maven", name);
16
16
  this.group = group;
17
+ this.classifier = classifier;
17
18
  this.version = version;
18
19
 
19
20
  final StringBuilder fullNameBuilder = new StringBuilder();
@@ -23,6 +24,10 @@ public final class MavenPluginType
23
24
  fullNameBuilder.append(name);
24
25
  fullNameBuilder.append(":");
25
26
  fullNameBuilder.append(version);
27
+ if (classifier != null) {
28
+ fullNameBuilder.append(":");
29
+ fullNameBuilder.append(classifier);
30
+ }
26
31
  this.fullName = fullNameBuilder.toString();
27
32
 
28
33
  final HashMap<String, String> fullMapMutable = new HashMap<String, String>();
@@ -33,12 +38,13 @@ public final class MavenPluginType
33
38
  this.fullMap = Collections.unmodifiableMap(fullMapMutable);
34
39
  }
35
40
 
36
- public static MavenPluginType create(final String name, final String group, final String version)
41
+ public static MavenPluginType create(
42
+ final String name, final String group, final String classifier, final String version)
37
43
  {
38
- if (name == null) {
39
- throw new NullPointerException("\"name\" must not present.");
44
+ if (name == null || group == null || version == null) {
45
+ throw new NullPointerException("\"name\", \"group\" and \"version\" must be present.");
40
46
  }
41
- return new MavenPluginType(name, group, version);
47
+ return new MavenPluginType(name, group, classifier, version);
42
48
  }
43
49
 
44
50
  @JsonValue
@@ -53,6 +59,12 @@ public final class MavenPluginType
53
59
  return this.group;
54
60
  }
55
61
 
62
+ @JsonProperty("classifier")
63
+ public final String getClassifier()
64
+ {
65
+ return this.classifier;
66
+ }
67
+
56
68
  @JsonProperty("version")
57
69
  public final String getVersion()
58
70
  {
@@ -67,7 +79,7 @@ public final class MavenPluginType
67
79
  @Override
68
80
  public final int hashCode()
69
81
  {
70
- return Objects.hash(getSourceType(), getName(), this.group, this.version);
82
+ return Objects.hash(getSourceType(), getName(), this.group, this.classifier, this.version);
71
83
  }
72
84
 
73
85
  @Override
@@ -80,6 +92,8 @@ public final class MavenPluginType
80
92
  return (this.getSourceType().equals(other.getSourceType()) &&
81
93
  this.getName().equals(other.getName()) &&
82
94
  this.getGroup().equals(other.getGroup()) &&
95
+ ((this.getClassifier() == null && other.getClassifier() == null) ||
96
+ (this.getClassifier() != null && this.getClassifier().equals(other.getClassifier()))) &&
83
97
  this.getVersion().equals(other.getVersion()));
84
98
  }
85
99
 
@@ -91,6 +105,7 @@ public final class MavenPluginType
91
105
  }
92
106
 
93
107
  private final String group;
108
+ private final String classifier; // |classifier| can be null.
94
109
  private final String version;
95
110
  private final String fullName;
96
111
  private final Map<String, String> fullMap;
@@ -42,6 +42,15 @@ public class PluginClassLoader
42
42
  }));
43
43
  }
44
44
 
45
+ /**
46
+ * Adds the specified path to the list of URLs (for {@code URLClassLoader}) to search for classes and resources.
47
+ *
48
+ * It internally calls {@code URLClassLoader#addURL}.
49
+ *
50
+ * Some plugins (embulk-input-jdbc, for example) are calling this method to load external JAR files.
51
+ *
52
+ * @see https://github.com/embulk/embulk-input-jdbc/blob/ebfff0b249d507fc730c87e08b56e6aa492060ca/embulk-input-jdbc/src/main/java/org/embulk/input/jdbc/AbstractJdbcInputPlugin.java#L586-L595
53
+ */
45
54
  public void addPath(Path path)
46
55
  {
47
56
  try {
@@ -56,17 +65,45 @@ public class PluginClassLoader
56
65
  super.addURL(url);
57
66
  }
58
67
 
68
+ /**
69
+ * Loads the class with the specified binary name prioritized by the "parent-first" condition.
70
+ *
71
+ * It copy-cats {@code ClassLoader#loadClass} while the "parent-first" priorities are considered.
72
+ *
73
+ * If the specified class is "parent-first", it behaves the same as {@code ClassLoader#loadClass} ordered as below.
74
+ *
75
+ * <ol>
76
+ *
77
+ * <li><p>Invoke the {@code #findLoadedClass} method to check if the class has already been loaded.</p></li>
78
+ *
79
+ * <li><p>Invoke the parent's {@code #loadClass} method.
80
+ *
81
+ * <li><p>Invoke the {@code #findClass} method of this class loader to find the class.</p></li>
82
+ *
83
+ * </ol>
84
+ *
85
+ * If the specified class is "NOT parent-first", the 2nd and 3rd actions are swapped.
86
+ *
87
+ * @see https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#loadClass(java.lang.String,%20boolean)
88
+ * @see http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/jdk7u141-b02/src/share/classes/java/lang/ClassLoader.java
89
+ */
59
90
  @Override
60
91
  protected Class<?> loadClass(String name, boolean resolve)
61
92
  throws ClassNotFoundException
62
93
  {
63
94
  synchronized (getClassLoadingLock(name)) {
64
- Class<?> loadedClass = findLoadedClass(name);
95
+ // If the class has already been loaded by this {@code ClassLoader} or the parent's {@code ClassLoader},
96
+ // find the loaded class and return it.
97
+ final Class<?> loadedClass = findLoadedClass(name);
98
+
65
99
  if (loadedClass != null) {
66
100
  return resolveClass(loadedClass, resolve);
67
101
  }
68
102
 
69
- boolean parentFirst = isParentFirstPackage(name);
103
+ final boolean parentFirst = isParentFirstPackage(name);
104
+
105
+ // If the class is "not parent-first" (not to be loaded by the parent at first),
106
+ // try {@code #findClass} of the child's ({@code PluginClassLoader}'s).
70
107
  if (!parentFirst) {
71
108
  try {
72
109
  return resolveClass(findClass(name), resolve);
@@ -74,11 +111,14 @@ public class PluginClassLoader
74
111
  }
75
112
  }
76
113
 
114
+ // If the class is "parent-first" (to be loaded by the parent at first), try this part at first.
115
+ // If the class is "not parent-first" (not to be loaded by the parent at first), the above part runs first.
77
116
  try {
78
117
  return resolveClass(getParent().loadClass(name), resolve);
79
118
  } catch (ClassNotFoundException ignored) {
80
119
  }
81
120
 
121
+ // If the class is "parent-first" (to be loaded by the parent at first), this part runs after the above.
82
122
  if (parentFirst) {
83
123
  return resolveClass(findClass(name), resolve);
84
124
  }
@@ -5,6 +5,7 @@ public class PluginSourceNotMatchException
5
5
  {
6
6
  public PluginSourceNotMatchException()
7
7
  {
8
+ super();
8
9
  }
9
10
 
10
11
  public PluginSourceNotMatchException(String message)
@@ -16,4 +17,9 @@ public class PluginSourceNotMatchException
16
17
  {
17
18
  super(cause);
18
19
  }
20
+
21
+ public PluginSourceNotMatchException(String message, Throwable cause)
22
+ {
23
+ super(message, cause);
24
+ }
19
25
  }
@@ -79,8 +79,9 @@ public abstract class PluginType
79
79
  {
80
80
  final String name = stringMap.get("name");
81
81
  final String group = stringMap.get("group");
82
+ final String classifier = stringMap.get("classifier");
82
83
  final String version = stringMap.get("version");
83
- return MavenPluginType.create(name, group, version);
84
+ return MavenPluginType.create(name, group, classifier, version);
84
85
  }
85
86
  default:
86
87
  throw new IllegalArgumentException("\"source\" must be one of: [\"default\", \"maven\"]");
@@ -0,0 +1,14 @@
1
+ package org.embulk.plugin.jar;
2
+
3
+ public class InvalidJarPluginException
4
+ extends Exception {
5
+ public InvalidJarPluginException(final String message)
6
+ {
7
+ super(message);
8
+ }
9
+
10
+ public InvalidJarPluginException(final String message, final Throwable cause)
11
+ {
12
+ super(message, cause);
13
+ }
14
+ }
@@ -0,0 +1,205 @@
1
+ package org.embulk.plugin.jar;
2
+
3
+ import com.google.common.collect.ImmutableList;
4
+ import java.io.IOError;
5
+ import java.io.IOException;
6
+ import java.net.JarURLConnection;
7
+ import java.net.MalformedURLException;
8
+ import java.net.URI;
9
+ import java.net.URL;
10
+ import java.nio.file.Path;
11
+ import java.util.jar.Attributes;
12
+ import java.util.jar.Manifest;
13
+ import org.embulk.plugin.PluginClassLoader;
14
+ import org.embulk.plugin.PluginClassLoaderFactory;
15
+
16
+ /**
17
+ * JarPluginLoader loads a JAR-based Embulk plugin class.
18
+ *
19
+ * It implements {@code AutoCloseable} so that it can load the contents lazily in the future.
20
+ * It is recommended to try-with-resources to use this class.
21
+ */
22
+ public class JarPluginLoader
23
+ implements AutoCloseable
24
+ {
25
+ public static final String MANIFEST_PLUGIN_MAIN_CLASS = "Embulk-Plugin-Main-Class";
26
+ public static final String MANIFEST_PLUGIN_SPI_VERSION = "Embulk-Plugin-Spi-Version";
27
+
28
+ private JarPluginLoader(final Manifest pluginManifest,
29
+ final Attributes pluginManifestAttributes,
30
+ final Class pluginMainClass)
31
+ {
32
+ this.pluginManifest = pluginManifest;
33
+ this.pluginManifestAttributes = pluginManifestAttributes;
34
+ this.pluginMainClass = pluginMainClass;
35
+ }
36
+
37
+ public static JarPluginLoader load(final Path jarPath, final PluginClassLoaderFactory classLoaderFactory)
38
+ throws InvalidJarPluginException
39
+ {
40
+ final JarURLConnection connection = openJarURLConnection(jarPath);
41
+ final Manifest manifest = loadJarPluginManifest(connection, jarPath);
42
+ final Attributes manifestAttributes = manifest.getMainAttributes();
43
+ final int spiVersion = getPluginSpiVersionFromManifest(manifestAttributes);
44
+
45
+ if (spiVersion == 0) {
46
+ final String mainClassName = getPluginMainClassNameFromManifest(manifestAttributes);
47
+ final Class mainClass = loadJarPluginMainClass(jarPath, mainClassName, classLoaderFactory);
48
+ return new JarPluginLoader(manifest, manifestAttributes, mainClass);
49
+ }
50
+
51
+ throw new InvalidJarPluginException("Unknown SPI version of JAR plugin: " + spiVersion);
52
+ }
53
+
54
+ public Class getPluginMainClass()
55
+ throws InvalidJarPluginException
56
+ {
57
+ return this.pluginMainClass;
58
+ }
59
+
60
+ public int getPluginSpiVersion()
61
+ throws InvalidJarPluginException
62
+ {
63
+ return getPluginSpiVersionFromManifest(this.pluginManifestAttributes);
64
+ }
65
+
66
+ @Override
67
+ public void close()
68
+ throws InvalidJarPluginException
69
+ {
70
+ }
71
+
72
+ /**
73
+ * Opens JarURLConnection for the given JAR file path.
74
+ *
75
+ * Note that JarURLConnection does not have {@code disconnect} nor {@code close}.
76
+ */
77
+ private static JarURLConnection openJarURLConnection(final Path jarPath)
78
+ throws InvalidJarPluginException
79
+ {
80
+ // jar:file:/...
81
+ final URL jarUrl;
82
+ try {
83
+ jarUrl = new URL("jar:" + jarPath.toUri().toURL().toString() + "!/");
84
+ }
85
+ catch (MalformedURLException ex) {
86
+ throw new InvalidJarPluginException("JAR plugin path specified is invalid: " + jarPath.toString(), ex);
87
+ }
88
+
89
+ try {
90
+ return (JarURLConnection) jarUrl.openConnection();
91
+ }
92
+ catch (IOException ex) {
93
+ throw new InvalidJarPluginException("JAR plugin specified is formatted wrongly: " + jarPath.toString(), ex);
94
+ }
95
+ }
96
+
97
+ private static Manifest loadJarPluginManifest(final JarURLConnection connection, final Path jarPath)
98
+ throws InvalidJarPluginException
99
+ {
100
+ try {
101
+ return connection.getManifest();
102
+ }
103
+ catch (IOException ex) {
104
+ throw new InvalidJarPluginException("Manifest in JAR plugin specified is invalid: " + jarPath.toString(),
105
+ ex);
106
+ }
107
+ }
108
+
109
+ private static Class loadJarPluginMainClass(final Path jarPath,
110
+ final String pluginMainClassName,
111
+ final PluginClassLoaderFactory pluginClassLoaderFactory)
112
+ throws InvalidJarPluginException
113
+ {
114
+ final URI fileUriJar;
115
+ try {
116
+ fileUriJar = jarPath.toUri();
117
+ }
118
+ catch (IOError ex) {
119
+ throw new InvalidJarPluginException("[FATAL] JAR plugin path specified is invalid: " + jarPath.toString(),
120
+ ex);
121
+ }
122
+ catch (SecurityException ex) {
123
+ throw new InvalidJarPluginException("Security manager prohibits getting the working directory: " +
124
+ jarPath.toString() +
125
+ ". Specifying an absolute path for JAR plugin may solve this.",
126
+ ex);
127
+ }
128
+
129
+ // file:/...
130
+ final URL fileUrlJar;
131
+ try {
132
+ fileUrlJar = fileUriJar.toURL();
133
+ }
134
+ catch (IllegalArgumentException ex) {
135
+ throw new InvalidJarPluginException("[FATAL/INTERNAL] JAR plugin path as URI is not absolute.", ex);
136
+ }
137
+ catch (MalformedURLException ex) {
138
+ throw new InvalidJarPluginException("JAR plugin path specified is invalid: " + jarPath.toString(), ex);
139
+ }
140
+
141
+
142
+ final PluginClassLoader pluginClassLoader =
143
+ pluginClassLoaderFactory.create(ImmutableList.of(fileUrlJar), JarPluginLoader.class.getClassLoader());
144
+
145
+ final Class pluginMainClass;
146
+ try {
147
+ pluginMainClass = pluginClassLoader.loadClass(pluginMainClassName);
148
+ }
149
+ catch (ClassNotFoundException ex) {
150
+ throw new InvalidJarPluginException("Class " + pluginMainClassName + " not found in " + jarPath.toString(),
151
+ ex);
152
+ }
153
+
154
+ return pluginMainClass;
155
+ }
156
+
157
+ private static int getPluginSpiVersionFromManifest(final Attributes manifestAttributes)
158
+ throws InvalidJarPluginException
159
+ {
160
+ final String spiVersionString = getAttributeFromManifest(manifestAttributes, MANIFEST_PLUGIN_SPI_VERSION);
161
+
162
+ if (spiVersionString == null) {
163
+ throw new InvalidJarPluginException("SPI version of JAR plugin is not specified.");
164
+ }
165
+
166
+ try {
167
+ return Integer.parseInt(spiVersionString);
168
+ }
169
+ catch (NumberFormatException ex) {
170
+ throw new InvalidJarPluginException("SPI version of JAR plugin is not an integer: \"" +
171
+ spiVersionString +
172
+ "\"", ex);
173
+ }
174
+ }
175
+
176
+ private static String getPluginMainClassNameFromManifest(final Attributes manifestAttributes)
177
+ throws InvalidJarPluginException
178
+ {
179
+ final String pluginMainClassName = getAttributeFromManifest(manifestAttributes, MANIFEST_PLUGIN_MAIN_CLASS);
180
+
181
+ if (pluginMainClassName == null) {
182
+ throw new InvalidJarPluginException("Main class name of JAR plugin is not specified.");
183
+ }
184
+
185
+ return pluginMainClassName;
186
+ }
187
+
188
+ private static String getAttributeFromManifest(final Attributes manifestAttributes, final String attributeName)
189
+ throws InvalidJarPluginException
190
+ {
191
+ try {
192
+ return manifestAttributes.getValue(attributeName);
193
+ }
194
+ catch (IllegalArgumentException ex) {
195
+ throw new InvalidJarPluginException("[FATAL/INTERNAL] " +
196
+ attributeName +
197
+ " is considered invalid as a manifest attribute.",
198
+ ex);
199
+ }
200
+ }
201
+
202
+ private final Manifest pluginManifest;
203
+ private final Attributes pluginManifestAttributes;
204
+ private final Class pluginMainClass;
205
+ }